A collection of tips to help take your CSS skills pro.
---
title: CSS Protips
subtitle: A collection of tips to help take your CSS skills pro.
author: "Matt Smith (AllThingsSmitty)"
date: May 16, 2021
source: https://github.com/AllThingsSmitty/css-protips
snippet: https://jonlabelle.com/snippets/view/markdown/css-protips
notoc: false
---
A collection of tips to help take your CSS skills pro.
> For other great lists check out
> [sindresorhus](https://github.com/sindresorhus/)'s curated list of
> [awesome lists](https://github.com/sindresorhus/awesome/).
## Use a CSS Reset
CSS resets help enforce style consistency across different browsers with a clean
slate for styling elements. You can use a CSS reset library like
[Normalize](http://necolas.github.io/normalize.css/), _et al._, or you can use a
more simplified reset approach:
```css
*,
*::before,
*::after {
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.
### [Demo](http://codepen.io/AllThingsSmitty/pen/kkrkLL)
**Note:** If you follow the [Inherit `box-sizing`](#inherit-box-sizing) tip
below you might opt to not include the `box-sizing` property in your CSS reset.
## Inherit `box-sizing`
Let `box-sizing` be inherited from `html`:
```css
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.
### [Demo](https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/)
## Use `unset` Instead of Resetting All Properties
When resetting an element's properties, it's not necessary to reset each
individual property:
```css
button {
background: none;
border: none;
color: inherit;
font: inherit;
outline: none;
padding: 0;
}
```
You can specify all of an element's properties using the `all` shorthand.
Setting the value to `unset` changes an element's properties to their initial
values:
```css
button {
all: unset;
}
```
**Note:** the `all` and `unset` shorthand isn't supported in IE11.
## Use `:not()` to Apply/Unapply Borders on Navigation
Instead of putting on the border...
```css
/* add border */
.nav li {
border-right: 1px solid #666;
}
```
...and then taking it off the last element...
```css
/* remove border */
.nav li:last-child {
border-right: none;
}
```
...use the `:not()` pseudo-class to only apply to the elements you want:
```css
.nav li:not(:last-child) {
border-right: 1px solid #666;
}
```
Here, the CSS selector is read as a human would describe it.
### [Demo](http://codepen.io/AllThingsSmitty/pen/LkymvO)
## Check If Font Is Installed Locally
You can check if a font is installed locally before fetching it remotely, which
is a good performance tip, too.
```css
@font-face {
font-family: "Dank Mono";
src:
/* Full name */ local("Dank Mono"), /* Postscript name */ local("Dank Mono"),
/* Otherwise, download it! */ url("//...a.server/fonts/DankMono.woff");
}
code {
font-family: "Dank Mono", system-ui-monospace;
}
```
H/T to Adam Argyle for sharing this protip and
[demo](https://codepen.io/argyleink/pen/VwYJpgR).
## Add `line-height` to `body`
You don't need to add `line-height` to each `<p>`, `<h*>`, _et al_. separately.
Instead, add it to `body`:
```css
body {
line-height: 1.5;
}
```
This way textual elements can inherit from `body` easily.
### [Demo](http://codepen.io/AllThingsSmitty/pen/VjbdYd)
## Set `:focus` for Form Elements
Sighted keyboard users rely on focus to determine where keyboard events go in
the page. Make focus for form elements stand out and consistent then a browser's
default implementation:
```css
a:focus,
button:focus,
input:focus,
select:focus,
textarea:focus {
box-shadow: none;
outline: #000 dotted 2px;
outline-offset: 0.05em;
}
```
### [Demo](https://codepen.io/AllThingsSmitty/pen/ePzoOP/)
## Vertically-Center Anything
No, it's not black magic, you really can center elements vertically. You can do
this with flexbox...
```css
html,
body {
height: 100%;
margin: 0;
}
body {
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-flex;
display: flex;
}
```
...and also with CSS Grid:
```css
body {
display: grid;
height: 100vh;
margin: 0;
place-items: center center;
}
```
Want to center something else? Vertically, horizontally...anything, anytime,
anywhere? CSS-Tricks has
[a nice write-up](https://css-tricks.com/centering-css-complete-guide/) on doing
all of that.
**Note:** Watch for some
[buggy behavior](https://github.com/philipwalton/flexbugs#3-min-height-on-a-flex-container-wont-apply-to-its-flex-items)
with flexbox in IE11.
### [Demo](http://codepen.io/AllThingsSmitty/pen/GqmGqZ)
## Comma-Separated Lists
Make list items look like a real, comma-separated list:
```css
ul > li:not(:last-child)::after {
content: ",";
}
```
Use the `:not()` pseudo-class and no comma will be 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.
## Select Items Using Negative `nth-child`
Use negative `nth-child` in CSS to select items 1 through n.
```css
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()`](#use-not-to-applyunapply-borders-on-navigation), try:
```css
/* select all items except the first 3 and display them */
li:not(:nth-child(-n + 3)) {
display: block;
}
```
### [Demo](http://codepen.io/AllThingsSmitty/pen/WxjKZp)
## Use SVG for Icons
There's no reason not to use SVG for icons:
```css
.logo {
background: url("logo.svg");
}
```
SVG scales well for all resolution types and is supported in all browsers
[back to IE9](http://caniuse.com/#search=svg). 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:
```css
.no-svg .icon-only::after {
content: attr(aria-label);
}
```
## Use the "Lobotomized Owl" Selector
It may have a strange name but using the universal selector (`*`) with the
adjacent sibling selector (`+`) can provide a powerful CSS capability:
```css
* + * {
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](http://alistapart.com/article/axiomatic-css-and-lobotomized-owls)
on _A List Apart_.
### [Demo](http://codepen.io/AllThingsSmitty/pen/grRvWq)
## Use `max-height` for Pure CSS Sliders
Implement CSS-only sliders using `max-height` with overflow hidden:
```css
.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.
## Equal-Width Table Cells
Tables can be a pain to work with. Try using `table-layout: fixed` to keep cells
at equal width:
```css
.calendar {
table-layout: fixed;
}
```
Pain-free table layouts.
### [Demo](http://codepen.io/AllThingsSmitty/pen/jALALm)
## Get Rid of Margin Hacks With Flexbox
When working with column gutters you can get rid of `nth-`, `first-`, and
`last-child` hacks by using flexbox's `space-between` property:
```css
.list {
display: flex;
justify-content: space-between;
}
.list .person {
flex-basis: 23%;
}
```
Now column gutters always appear evenly-spaced.
## Use Attribute Selectors with Empty Links
Display links when the `<a>` element has no text value but the `href` attribute
has a link:
```css
a[href^="http"]:empty::before {
content: attr(href);
}
```
That's pretty convenient.
### [Demo](http://codepen.io/AllThingsSmitty/pen/zBzXRx)
## Style "Default" Links
Add a style for "default" links:
```css
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.
## Intrinsic Ratio Boxes
To create a box with an intrinsic ratio, all you need to do is apply top or
bottom padding to a div:
```css
.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).
### [Demo](http://codepen.io/AllThingsSmitty/pen/jALZvE)
## Style Broken Images
Make broken images more aesthetically-pleasing with a little bit of CSS:
```css
img {
display: block;
font-family: 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:
```css
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](https://github.com/ireade/)'s
[original post](http://bitsofco.de/styling-broken-images/).
## Use `rem` for Global Sizing; Use `em` for Local Sizing
After setting the base font size at the root (`html { font-size: 100%; }`), set
the font size for textual elements to `em`:
```css
h2 {
font-size: 2em;
}
p {
font-size: 1em;
}
```
Then set the font-size for modules to `rem`:
```css
article {
font-size: 1.25rem;
}
aside .module {
font-size: 0.9rem;
}
```
Now each module becomes compartmentalized and easier to style, more
maintainable, and flexible.
## Hide Autoplay Videos That Aren't Muted
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:
```css
video[autoplay]:not([muted]) {
display: none;
}
```
Once again, we're taking advantage of using the
[`:not()`](#use-not-to-applyunapply-borders-on-navigation) pseudo-class.
## Use `:root` for Flexible Type
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`:
```css
:root {
font-size: calc(1vw + 1vh + 0.5vmin);
}
```
Now you can utilize the `root em` unit based on the value calculated by `:root`:
```css
body {
font: 1rem/1.6 sans-serif;
}
```
### [Demo](http://codepen.io/AllThingsSmitty/pen/XKgOkR)
## Set `font-size` on Form Elements for a Better Mobile Experience
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:
```css
input[type="text"],
input[type="number"],
select,
textarea {
font-size: 16px;
}
```
## Use Pointer Events to Control Mouse Events
[Pointer events](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events)
allow you to specify how the mouse interacts with the element it's touching. To
disable the default pointer event on a button, for instance:
```css
.button-disabled {
opacity: 0.5;
pointer-events: none;
}
```
It's that simple.
## Set `display: none` on Line Breaks Used as Spacing
As
[Harry Roberts pointed out](https://twitter.com/csswizardry/status/1170835532584235008),
this can help prevent CMS users from using extra line breaks for spacing:
```css
br + br {
display: none;
}
```
## Support
Current versions of Chrome, Firefox, Safari, Opera, Edge, and IE11.