Useful HTML and CSS Tricks for Web Developers
Practical HTML and CSS techniques for accessible controls, responsive layouts, images, component queries, and easier-to-maintain stylesheets.
Useful HTML and CSS tricks start with choosing the right semantic element, then letting browser layout features handle as much adaptation as possible. Use native controls for built-in behavior, flexible Grid or Flexbox layouts for content, media queries for viewport and user preferences, and container queries for components whose layout depends on their own available space.
This guide shows practical patterns, their boundaries, and how they fit together. The examples use browser-native HTML and CSS; adapt class names and thresholds to the content and layout of your own page.
1. Use the native element for the job
Use a <button> to perform an action and an <a href> to navigate. Native elements come with expected semantics and keyboard behavior. Styling a generic <div> to look like a button does not give it those behaviors automatically. See MDN’s guides to the button element and the anchor element.
<button type="button">Save changes</button>
<a href="/guides">Browse guides</a>
CSS can change how these controls look while preserving their behavior. Keep visual affordances recognizable and provide a visible focus style so keyboard users can tell which control is active.
.button {
font: inherit;
padding: 0.65rem 1rem;
border: 0;
border-radius: 0.4rem;
background: #174ea6;
color: white;
}
.button:focus-visible,
a:focus-visible {
outline: 3px solid #e49b00;
outline-offset: 3px;
}
Use a real link when activation changes location, and a button when it performs an action such as submitting, saving, or opening a dialog. If a control is unavailable, use the element’s native disabled behavior where appropriate instead of relying only on a visual style.
2. Let layout do the responsive work
Start with a layout that can flex naturally. Grid and Flexbox often handle changing available space without a breakpoint. A media query is useful when the viewport or environment calls for a specific change, but a layout should not need a device-specific breakpoint just because a device has a familiar name. MDN’s responsive design guide covers fluid layouts and media queries.
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
gap: 1rem;
}
.card {
min-width: 0;
}
img,
video {
max-inline-size: 100%;
}
auto-fit lets Grid fit as many columns as the available space allows, while minmax() sets a useful lower bound for each track. The nested min(100%, 16rem) prevents a minimum track width from forcing overflow in a very narrow container. The media rule limits an image or video to its available inline space; the commonly used equivalent for left-to-right layouts is max-width: 100%. This constrains oversized media but does not create an optimal source image for every display.
Choose Grid for two-dimensional arrangements of rows and columns, and Flexbox for a one-dimensional row or column whose items may grow, shrink, or wrap. If long words or unbreakable content still push a grid item wider than its track, min-width: 0 on the item can allow it to shrink; also decide how that content should wrap or overflow.
3. Use media queries for viewport and environment changes
A media query responds to conditions such as viewport width or a user preference. Use one when the content or layout needs to change at a particular condition. Avoid picking breakpoints solely to match device categories: the useful threshold is where the design stops working well.
@media (width < 40rem) {
.site-nav {
/* Switch to a compact presentation when the layout needs it. */
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto;
animation-duration: 0.01ms;
animation-iteration-count: 1;
transition-duration: 0.01ms;
}
}
The first query is an example threshold, not a universal mobile breakpoint. Review the actual navigation and content at widths around the chosen value. The reduced-motion example is also a starting point: check what each animation communicates, and ensure that removing or shortening motion does not hide important state changes. See MDN’s media query reference.
4. Let reusable components query their own width
A viewport query cannot tell whether the same card sits in a wide main column or a narrow sidebar. A container size query can respond to the component’s containing block, which makes it useful for reusable components placed in differently sized regions. Declare a query container, then style its descendants. See MDN’s references for container queries and the container-type property.
.article-slot {
container-type: inline-size;
}
.article-card {
display: grid;
gap: 1rem;
}
@container (width > 42rem) {
.article-card {
grid-template-columns: 12rem 1fr;
align-items: start;
}
}
The card is stacked by default and becomes a two-column layout when its eligible container is wide enough. Container queries apply to descendants of the nearest eligible container. container-type: inline-size establishes inline-size containment; container-type: size allows querying both dimensions and applies broader containment. Choose the type deliberately because containment affects layout behavior.
Use a media query when the change is driven by the page viewport or environment. Use a container query when a component needs to adapt to its allocated region. Natural wrapping with Grid or Flexbox is often simpler when no discrete layout change is required.
5. Deliver images suited to the display
For a fluid image, constrain its rendered size. When you have alternate source resolutions or crops, responsive image markup lets the browser choose from the resources you provide. MDN explains responsive images and the <img> element.
<img
src="landscape-800.jpg"
srcset="landscape-400.jpg 400w, landscape-800.jpg 800w, landscape-1600.jpg 1600w"
sizes="(max-width: 40rem) 100vw, 50vw"
width="1600"
height="900"
alt="A developer reviewing a responsive page layout"
>
The width descriptors in srcset describe the available resource widths. The sizes value estimates the image’s rendered slot so the browser can choose an appropriate candidate. Update it to match the real layout; a mismatched value can lead the browser to choose a source that is larger or smaller than needed. The example assumes the image fills the viewport below 40rem and occupies half the viewport above it. Responsive markup can help serve suitable resources, but it is not a performance guarantee by itself.
Set dimensions that match the source aspect ratio to reserve space while the image loads. Write alternative text that conveys the purpose of informative images; use empty alternative text for decorative images so assistive technology can skip them. For art direction, use <picture> with sources for alternate crops rather than expecting srcset alone to change the composition.
6. Organize precedence with cascade layers
When a stylesheet combines a reset, vendor styles, components, and utilities, cascade layers make the intended precedence explicit. They can reduce specificity fights by letting you order groups of rules instead of making selectors increasingly specific. Read MDN’s cascade layers guide when introducing layers into an existing cascade.
@layer reset, vendor, base, components, utilities;
@layer base {
body {
margin: 0;
}
}
@layer components {
.button {
border-radius: 0.4rem;
}
}
Declare the layer order deliberately, especially when importing third-party CSS. Layer order participates in the cascade, so a rule in a later layer can take precedence over a rule in an earlier layer without needing a more specific selector. Unlayered author styles have their own cascade position relative to layered styles, so check how existing rules interact before adding layers. Browser developer tools can show which declarations matched and which ones lost in the cascade.
7. Gate newer CSS with feature queries
A feature query checks whether a browser supports a CSS capability; a media query checks viewing conditions. Start with a usable baseline and add an enhancement inside @supports. MDN documents feature queries.
.card-list {
display: block;
}
.card-list > * + * {
margin-block-start: 1rem;
}
@supports (display: grid) {
.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1rem;
}
.card-list > * + * {
margin-block-start: 0;
}
}
The fallback remains a vertical list, while supporting browsers receive the grid layout. Check that the fallback is acceptable for your content and verify support for the exact feature and syntax you plan to use. Feature queries do not replace testing the rendered result.
8. Choose the technique that matches the cause
| Need | Start with | Why |
|---|---|---|
| Controls with expected behavior | Semantic HTML elements | Native elements supply semantics and interaction behavior. |
| A layout that adapts as space changes | Grid or Flexbox | Content-driven layout can avoid unnecessary breakpoints. |
| A change based on viewport or user preference | Media query | The condition belongs to the viewing environment. |
| A reusable component in differently sized regions | Container query | The component responds to its own available space. |
| Alternative image sources or crops | srcset, sizes, or picture |
The browser can select from appropriate resources you supply. |
| Styles from several sources need predictable precedence | Cascade layers | Layer order expresses group priority. |
| A newer CSS feature needs a fallback | @supports |
Enhancement is applied only when the browser supports the feature. |
9. A practical review checklist
- Use a link for navigation and a button for an action.
- Check focus visibility and keyboard operation for interactive controls.
- Let Grid or Flexbox handle natural resizing before adding breakpoints.
- Test at widths just above and below each media or container query threshold.
- Give media a size constraint and ensure responsive image hints reflect its actual rendered slot.
- Set cascade layer order before the stylesheet grows across multiple sources.
- Keep a usable fallback when gating a feature with
@supports.
10. Troubleshooting common problems
Buttons or links do not work with a keyboard
Cause: A generic element was styled to look interactive, or focus styling was removed. Fix: Use a native <button> for an action or an <a href> for navigation, and provide a visible :focus-visible style.
A grid overflows its narrow parent
Cause: A track minimum or an unbreakable child is wider than the available space. Fix: Use a flexible minimum such as minmax(min(100%, 16rem), 1fr), allow grid items to shrink with min-width: 0, and decide how long content should wrap or scroll.
A container query never activates
Cause: No ancestor establishes the required query container, or the rule targets an element that is not a descendant of that container. Fix: Add container-type: inline-size to the intended wrapper, confirm the queried component is inside it, and inspect the wrapper’s computed width.
An image is too large or blurry
Cause: The sizes estimate does not match the image’s rendered width, or the provided sources do not include a suitable resolution. Fix: Match the sizes conditions to the layout and provide source candidates appropriate for the expected display sizes.
A CSS declaration loses unexpectedly
Cause: A competing rule wins due to cascade order, layer position, specificity, or importance. Fix: Inspect matched rules in developer tools, establish layer order intentionally, and simplify the competing rules rather than escalating selector specificity without understanding the cascade.
The enhancement is absent in one browser
Cause: That browser does not support the feature or syntax used. Fix: Check current compatibility for the exact feature, keep the baseline useful, and use @supports where a conditional enhancement is appropriate.
11. Performance, reliability, and maintenance
These techniques do not require a JavaScript layout framework. A naturally flexible layout can reduce breakpoint-specific rules to maintain, while container queries can keep reusable component styles tied to the component’s region. Responsive image markup gives the browser options for selecting an asset, but only well-chosen sources and a realistic sizes value can make those options useful.
For reliability, test the actual rendered page at the query boundaries, with keyboard navigation, with reduced motion enabled, and in browsers relevant to your audience. Keep fallback styles usable when enhancing newer capabilities. For maintainability, choose layer order early, keep layout thresholds tied to content, and document exceptions that cannot be expressed with a simple fluid layout.
12. Capture the result for review
After refining a responsive page, a screenshot can help document how a layout appears at a chosen viewport or in a bug report. For full-page screenshots and responsive visual review, ScreenshotNeo is a website screenshot API and MCP server for developers. It can return a PNG, JPEG, WebP, or PDF from a URL.
Or skip the browser setup
Use this cURL request to capture a page. See the ScreenshotNeo API documentation for the request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Sign up for 1,000 free screenshots a month, with no card.
FAQ
Should I use Grid or Flexbox?
Use Grid when you are arranging rows and columns together; use Flexbox when items flow along one axis. Try the simplest layout that matches the content.
Do container queries replace media queries?
No. Container queries respond to a component’s containing block; media queries respond to viewport or environment conditions. A page can use both.
Does max-width: 100% make an image responsive?
It prevents the rendered image from exceeding its available width. Use responsive image markup as well when different source sizes or crops are needed.
Do cascade layers remove the need for specificity?
No. Specificity still applies within the cascade. Layers add an explicit ordering between groups of styles, which can reduce the need to increase specificity to resolve conflicts.


