CSS Protips Awesome
A collection of tips to help take your CSS skills pro.
For other great lists check out @sindresorhus's curated list of awesome lists.
- Use a CSS Reset
- Inherit
box-sizing - Use
:not()to Apply/Unapply Borders on Navigation - Add
line-heighttobody - Vertically-Center Anything
- Comma-Separated Lists
- Select Items Using Negative
nth-child - Use SVG for Icons
- Use the "Lobotomized Owl" Selector
- Use
max-heightfor Pure CSS Sliders - Equal-Width Table Cells
- Get Rid of Margin Hacks With Flexbox
- Use Attribute Selectors with Empty Links
- Style "Default" Links
- Consistent Vertical Rhythm
- Intrinsic Ratio Boxes
- Style Broken Images
- Use
remfor Global Sizing; Useemfor Local Sizing - Hide Autoplay Videos That Aren't Muted
- Use
:rootfor Flexible Type - Set
font-sizeon Form Elements for a Better Mobile Experience
CSS resets help enforce style consistency across different browsers with a clean slate for styling elements. You can use CSS reset library like Normalize, et al., or you can use a more simplified reset approach:
* { box-sizing: border-box; margin: 0; padding: 0; }
Now elements will be stripped of margins and padding, and box-sizing lets you manage layouts with the CSS box model.
Note: If you follow the Inherit box-sizing tip below you might opt to not include the box-sizing property in your CSS reset.
Let box-sizing be inherited from html:
html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; }
This makes it easier to change box-sizing in plugins or other components that leverage other behavior.
Instead of putting on the border...
/* add border */ .nav li { border-right: 1px solid #666; }
...and then taking it off the last element...
/* remove border */ .nav li:last-child { border-right: none; }
...use the :not() pseudo-class to only apply to the elements you want:
.nav li:not(:last-child) { border-right: 1px solid #666; }
Sure, you can use .nav li + li or even .nav li:first-child ~ li, but with :not() the intent is very clear and the CSS selector defines the border the way a human would describe it.
You don't need to add line-height to each <p>, <h*>, et al. separately. Instead, add it to body:
body { line-height: 1.5; }
This way textual elements can inherit from body easily.
No, it's not black magic, you really can center elements vertically:
html, body { height: 100%; margin: 0; } body { -webkit-align-items: center; -ms-flex-align: center; align-items: center; display: -webkit-flex; display: flex; }
Want to center something else? Vertically, horizontally...anything, anytime, anywhere? CSS-Tricks has a nice write-up on doing all of that.
Note: Watch for some buggy behavior with flexbox in IE11.
Make list items look like a real, comma-separated list:
ul > li:not(:last-child)::after { content: ","; }
Use the :not() pseudo-class so no comma is added to the last item.
Note: This tip may not be ideal for accessibility, specifically screen readers. And copy/paste from the browser doesn't work with CSS-generated content. Proceed with caution.
Use negative nth-child in CSS to select items 1 through n.
li { display: none; } /* select items 1 through 3 and display them */ li:nth-child(-n+3) { display: block; }
Or, since you've already learned a little about using :not(), try:
/* select items 1 through 3 and display them */ li:not(:nth-child(-n+3)) { display: none; }
Well that was pretty easy.
There's no reason not to use SVG for icons:
.logo { background: url("logo.svg"); }
SVG scales well for all resolution types and is supported in all browsers back to IE9. So ditch your .png, .jpg, or .gif-jif-whatev files.
Note: If you have SVG icon-only buttons for sighted users and the SVG fails to load, this will help maintain accessibility:
.no-svg .icon-only:after { content: attr(aria-label); }
It may have a strange name but using the universal selector (*) with the adjacent sibling selector (+) can provide a powerful CSS capability:
* + * { margin-top: 1.5em; }
In this example, all elements in the flow of the document that follow other elements will receive margin-top: 1.5em.
For more on the "lobotomized owl" selector, read Heydon Pickering's post on A List Apart.
Implement CSS-only sliders using max-height with overflow hidden:
.slider { max-height: 200px; overflow-y: hidden; width: 300px; } .slider:hover { max-height: 600px; overflow-y: scroll; }
The element expands to the max-height value on hover and the slider displays as a result of the overflow.
Tables can be a pain to work with so try using table-layout: fixed to keep cells at equal width:
.calendar { table-layout: fixed; }
Pain-free table layouts.
When working with column gutters you can get rid of nth-, first-, and last-child hacks by using flexbox's space-between property:
.list { display: flex; justify-content: space-between; } .list .person { flex-basis: 23%; }
Now column gutters always appear evenly-spaced.
Display links when the <a> element has no text value but the href attribute has a link:
a[href^="http"]:empty::before { content: attr(href); }
That's pretty convenient.
Add a style for "default" links:
a[href]:not([class]) { color: #008000; text-decoration: underline; }
Now links that are inserted via a CMS, which don't usually have a class attribute, will have a distinction without generically affecting the cascade.
Use a universal selector (*) within an element to create a consistent vertical rhythm:
.intro > * { margin-bottom: 1.25rem; }
Consistent vertical rhythm provides a visual aesthetic that makes content far more readable.
To create a box with an intrinsic ratio, all you need to do is apply top or bottom padding to a div:
.container { height: 0; padding-bottom: 20%; position: relative; } .container div { border: 2px dashed #ddd; height: 100%; left: 0; position: absolute; top: 0; width: 100%; }
Using 20% for padding makes the height of the box equal to 20% of its width. No matter the width of the viewport, the child div will keep its aspect ratio (100% / 20% = 5:1).
Make broken images more aesthetically-pleasing with a little bit of CSS:
img { display: block; font-family: Helvetica, Arial, sans-serif; font-weight: 300; height: auto; line-height: 2; position: relative; text-align: center; width: 100%; }
Now add pseudo-elements rules to display a user message and URL reference of the broken image:
img:before { content: "We're sorry, the image below is broken :("; display: block; margin-bottom: 10px; } img:after { content: "(url: " attr(src) ")"; display: block; font-size: 12px; }
Learn more about styling for this pattern in Ire Aderinokun's original post.
After setting the base font size at the root (html { font-size: 100%; }), set the font size for textual elements to em:
h2 { font-size: 2em; } p { font-size: 1em; }
Then set the font-size for modules to rem:
article { font-size: 1.25rem; } aside .module { font-size: .9rem; }
Now each module becomes compartmentalized and easier to style, more maintainable, and flexible.
This is a great trick for a custom user stylesheet. Avoid overloading a user with sound from a video that autoplays when the page is loaded. If the sound isn't muted, don't show the video:
video[autoplay]:not([muted]) { display: none; }
Once again, we're taking advantage of using the :not() pseudo-class.
The type font size in a responsive layout should be able to adjust with each viewport. You can calculate the font size based on the viewport height and width using :root:
:root { font-size: calc(1vw + 1vh + .5vmin); }
Now you can utilize the root em unit based on the value calculated by :root:
body { font: 1rem/1.6 sans-serif; }
To avoid mobile browsers (iOS Safari, et al.) from zooming in on HTML form elements when a <select> drop-down is tapped, add font-size to the selector rule:
input[type="text"], input[type="number"], select, textarea { font-size: 16px; }
💃
Current versions of Chrome, Firefox, Safari, Opera, Edge, and IE11.