Dashboard Layout, Cascade, and Cumulative Layout Shift
Orbit Analytics has a dashboard with a fixed left sidebar of 280px, main content with a 760px minimum, and a right rail of 320px. At a 1024px viewport the page scrolls horizontally; at 375px the sidebar covers the content. The CSS uses float: left, margin-left: -100%, and !important to override a vendor stylesheet. The sidebar uses height: 100vh, so its bottom navigation is hidden behind the mobile browser toolbar. Cards use width: 33.33% plus 24px padding and a 1px border, which overflows their container. Dark mode is applied by inline styles on <body>. A pulsing status dot runs animation: pulse 1s infinite and ignores reduced-motion preferences. The print stylesheet prints the sidebar and a dark background. Lighthouse reports CLS 0.31 from images without dimensions and a late-loading web font that shifts headings. The team wants no JavaScript for layout.
1. Choose a layout model and rewrite the shell so the dashboard adapts from three columns to one without horizontal scrolling at 375px. Account for padding and borders in the sizing.
Read the worked answer
Replace floats and negative margins with CSS Grid on the page shell: display: grid; grid-template-columns: 280px minmax(0, 1fr) 320px;. The minmax(0, 1fr) is important because a plain 1fr has an automatic minimum based on content and can force overflow. Add box-sizing: border-box globally so the cards' 24px padding and 1px border are included in their width. For the cards, use grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)) and remove the fixed 33.33%. Add a breakpoint, for example @media (max-width: 1100px), that collapses to grid-template-columns: 280px minmax(0, 1fr) and moves the right rail below the main content, and a second breakpoint at 700px that uses a single column and turns the sidebar into a normal block above the content. Replace height: 100vh with min-height: 100dvh where supported, with a 100vh fallback, so mobile browser chrome does not hide the bottom navigation. Test at 320px, 375px, 768px, 1024px, and 1440px with long product names and zoom at 200%.
2. The `!important` override and inline dark-mode styles are causing maintenance problems. Propose a cascade strategy that removes both while preserving the vendor stylesheet.
Read the worked answer
Inline styles on <body> beat normal author rules and force every dark-mode change to be a DOM mutation. Move the theme into a class or data attribute on <html>: :root defines light custom properties, [data-theme="dark"] overrides them, and components consume var(--surface), var(--text), and so on. This keeps specificity low and makes the toggle a single attribute change. For the vendor stylesheet, stop using !important as a first resort. First inspect which selector wins; if the vendor rule is a single class, a more specific component selector such as .dashboard .card may be enough. If the vendor file is loaded before the site stylesheet, normal source order may already solve it. Where the vendor uses !important, scope an override with @layer if supported: put vendor imports in a lower layer and site rules in a higher layer. If layers are not viable, use one narrowly scoped !important with a comment and a regression test, not a global override. Add print rules that hide the sidebar via display: none and force background: #fff; color: #000.
3. Reduce CLS from 0.31 and respect reduced-motion without adding layout JavaScript. List the specific CSS techniques and the order you would apply them.
Read the worked answer
CLS comes from two sources here: images without intrinsic dimensions and a web font that changes heading metrics after load. For images, add width and height attributes so the browser reserves the correct aspect ratio, then use img { max-width: 100%; height: auto; }; alternatively set aspect-ratio on the image container. For the font, use font-display: optional or swap with a metric-compatible fallback, and preload only the one critical font file. size-adjust, ascent-override, and descent-override in an @font-face fallback can reduce the shift further. For the pulsing dot, wrap the animation in @media (prefers-reduced-motion: no-preference) rather than animating unconditionally, or set animation: none under @media (prefers-reduced-motion: reduce). Apply in this order: reserve image space first because it is the largest and cheapest win, then fix font loading metrics, then gate motion. Re-measure CLS with throttled network and a cold cache, and check that the dark-mode custom properties do not cause a flash by setting the theme attribute before first paint.