CSS has been around for 25+ years, gaining tons of features and selectors to create great websites and apps. In this article, we'll explore popular and unique tricks to make your website stand out, plus older tricks that still work.
Some may look trivial, but they might not be for certain folks.
We'll also examine different layout implementations, scroll snapping, image shapes, and animation tricks. Let's dive in and explore some CSS tricks you should know!
Buttery smooth carousels with scroll-snap
You can create smooth snapping product carousels with scroll snap. Steve did an awesome video a while ago about this.
đĄ Learn more about it on MDN.
Hereâs a demo showing how to do it on either the x-axis
or y-axis
:
Layout
Sticky header and footer
There are different ways to implement sticky headers and footers.
The primary use case for this might be that you want to have your navigation always visible to the user. Or you might want to have some sort of mobile-like bottom navigation and just have your brand always in view.
There are 2 straight forward approaches that I like:
-
Using
position: sticky;
/* The Essential bit */
header {
position: sticky;
top: 0;
}
footer {
position: sticky;
bottom: 0;
}
- With CSS Grid:
/* The Essential bit */
body {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header"
"main"
"footer";
}
header {
grid-area: header;
}
main {
grid-area: main;
}
footer {
grid-area: footer;
}
You might have an easier time understanding the sticky positioning, after all, itâs in the name đ .
However, one neat thing about the grid implementation, is that if you remove the overflow: auto
property, the main content will push down the footer to the bottom.
Thatâs true to the sticky example as well, just remove the position: sticky
from the footer
and it will do the same.
The grid way is just a more robust solution in case you want to lay out your main content in a variety of ways.
2 Column sticky scroll
Props to Tom for making this concept easy to understand and implement.
<body>
<header>
On top
</header>
<section>
<div class="title-section">
On Left
</div>
<div class="c-sections">
<div class="content-section">content</div>
<div class="content-section">on right side</div>
<div class="content-section">to scroll through</div>
</div>
</section>
<footer></footer>
</body>
/* The Essential bits */
/* make the content cover the viewport */
header,
.title-section,
.content-section {
height: 100vh;
}
/* create 2 colums for the section element */
section {
display: grid;
grid-template-columns: 1fr 1fr;
}
/* make the left side stick to the top which allows the right side to scroll */
.title-section {
position: sticky;
top: 0;
}
Animation with CSS Custom properties
There are some caveats to using CSS vars in your design systems. But overall, they have been a game changer in web development.
Defining a variable is pretty straightforward, and is done like this:
:root {
--color-primary: dodgerblue;
}
/* Then we could use it, like so: */
.my-class {
color: var(--color-primary);
}
/* We could also add a fallback.
Here, we have forgot to declare --color-secondary,
so the background color would be hotpink.
*/
.my-class {
background-color: var(--color-secondary, hotpink);
}
The animation-delay
trick
You can do awesome things with CSS variables like control complex animations.
In the demo below, the secret ingredient is threefold:
-
animation-delay
with a negative value, causes the animation to start immediately. -
animation-play-state
set to paused initially, to only start when we want/need to. - The
--progress
custom property to allow control over the animation.
/* The essentials */
.my-element {
/* Setup */
animation-name: spin;
animation-timing-function: linear;
/* Here's the magic */
animation-play-state: paused;
animation-duration: 1s;
animation-delay: calc(var(--progress) * -1s);
/* These clean up some weirdness */
animation-iteration-count: 1;
animation-fill-mode: both;
}
Note, that in the below demo, there are more custom properties that control the color changes of the box and, of course, a little JavaScript to set our --progress
style on the element:
const root = document.querySelector("main");
const input = root.querySelector("input");
const animated = root.querySelector("#animated");
input.addEventListener("input", (event) => {
const min = Number(event.target.getAttribute("min"));
const max = Number(event.target.getAttribute("max"));
const value = Number(event.target.value);
const progress = (value - min) / max;
animated.style.setProperty("--progress", `${progress}`);
});
This is another demo that shows this method in practice, but in parallax style with a JS scroll listener:
Hover effects with box-shadow
There are a few keys to this trick:
-
box-shadow
values are:[inset?] [top] [left] [blur] [size] [color]
; - To get a solid fill,
blur
should be0
- Using
inset
allows to âfillâ our element - Negative values flip
top
/left
tobottom
/right
and vice versa - Multiple shadows can be stacked
- When animating multiple shadows, to achieve a smooth animation - keep the same number of shadows on hover/focus as non-hover/focus.
Hereâs how a âfill on hoverâ animation looks like:
<button class="fill">Fill In</button>
.fill {
--color: #a972cb;
--hover: #cb72aa;
}
.fill:hover,
.fill:focus {
box-shadow: inset 0 0 0 2em var(--hover);
}
button {
color: var(--color);
transition: 0.25s;
}
button:hover, button:focus {
border-color: var(--hover);
color: #fff;
}
button {
background: none;
border: 2px solid;
font: inherit;
line-height: 1;
margin: 0.5em;
padding: 1em 2em;
}
Check out some more cool animations with this method here:
Fixing nested border-radius with calculations
Syntax.FMâs Wes Bos has been doing some great videos over on TikTok. In one of his vids, he fixed Twitterâs new profile pics border radius for nested elements with this nifty trick:
.card-outer {
--radius: 20px;
--border: 5px;
/* Outer = Inner + space between */
border-radius: calc(var(--radius) + var(--border));
}
.card-inner {
margin: var(--border);
border-radius: var(--radius);
}
Centering an element both horizontally and vertically
Funny enough, this is still one of the most popular questions on stack overflow. Even Dan Abramov struggled with this in his mock interview with Ben Awad.
The old way
Before the introduction of flex-box
the way to achieve this was by using absolute positioning.
The general trick is so:
<div class="parent">
<div class="child">Center me</div>
</div>
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
The (now) common way
Flex-box is the most robust way to achieve centering nowadays, itâs even the example you get If you look at MDN.
<div class="parent">
<div class="child">Center me</div>
</div>
.parent {
display: flex;
justify-content: center;
align-items: center;
}
Flexbox works by being in charge of laying out its children. All we had to do to center it is use the properties that tell it to position the child in the horizontal center with justify-content
and vertical center with align-items
.
This is a much cleaner approach than the old way, but thereâs a newer way.
Hipster centering using grid
This might be the shortest way to achieve this feat.
<div class="parent">
<div class="child">Center me</div>
</div>
.parent {
display: grid;
place-content: center;
}
Once the parent is declared as a grid
we have this nifty property (place-content
) that just tells the browser to put the child in the center. If weâd add a sibling next to our <div>
it would also be centered and placed right under it.
Grid layout is supported on all major browsers nowadays, so why donât you give it a try?
Backdrop filters
Backdrop filters are cool and can be used for neomorphisim glass effect with backdrop-filter: blur
which is apparently not cool anymore.
Check out the documentation for backdrop-filter to learn more.
Handling image styles
Images on the web have come a long way, but a few good properties are a must-know:
-
object-fit
- helps with not stretching out images, as seen here. -
[aspect-ratio](https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio)
- as the name suggests, sets the preferred aspect ratio for boxes. You can get16 / 9
or3 / 4
boxes without ye ole padding aspect ratio hack. Again, Wes Bos has a great video showcasing this and more.
Shapes
There are a few ways to create shapes in CSS. The most common way is with borders and using the :before
and :after
pseudo classes.
You can use clip-path
to cut out shapes on any element.
For example, you can make a star shape with borders:
#star-five {
margin: 50px 0;
position: relative;
display: block;
color: red;
width: 0px;
height: 0px;
border-right: 100px solid transparent;
border-bottom: 70px solid red;
border-left: 100px solid transparent;
transform: rotate(35deg);
}
#star-five:before {
border-bottom: 80px solid red;
border-left: 30px solid transparent;
border-right: 30px solid transparent;
position: absolute;
height: 0;
width: 0;
top: -45px;
left: -65px;
display: block;
content: '';
transform: rotate(-35deg);
}
#star-five:after {
position: absolute;
display: block;
color: red;
top: 3px;
left: -105px;
width: 0px;
height: 0px;
border-right: 100px solid transparent;
border-bottom: 70px solid red;
border-left: 100px solid transparent;
transform: rotate(-70deg);
content: '';
}
Or you can achieve the same with clip-path
:
#star-five {
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}
When I find myself in need of a shape, I usually use this CSS clip-path maker by Bennett Feely.
svg
has an equivalent <clipPath>
element that you can use for the same results, as in this demo:
Debugging CSS
Knowing how to approach debugging is paramount. In fact, this tweet is what inspired this post:
Console.log in CSS
The key ways that came from the responses were:
/* 1 */
.element {
border: 1px solid red;
}
/* 2 */
.element {
background-color: red;
}
/* 3 */
.element {
outline: 1px solid red;
}
I use 2 and 3, as the first does add a pixel to the element's size. Why red? ÂŻ_(ă)_/ÂŻ
DevTools du jour
The devtools pan in all major browsers have improved immensely since the days of Firebug. You can debug z-index
issues with the layers pane. Changing CSS in the browser has never been easier, along with auto-complete. A few more cool features are:
- Color picker
- Flexbox editing
- Clip path editor
- Animation editor
- Device toolbar
Each deserves a post of itâs own, but if youâd like to learn more checkout the Google Chrome Devtools docs.
Bonus: style your console.log
Did you know you can add CSS properties to your JavaScript console.log
?
This is how you do it:
console.log(
// What comes after %c is what the styles will apply to
"This is %cMy stylish message",
// you can add multiple properties:
"color: yellow; font-style: italic; background-color: blue;padding: 2px"
);
Outputs:
// You could also style different parts of the console with multipule %c's:
console.log(
"Multiple styles: %cred %corange",
// style for first %c
"color: red",
// style for second %c
"color: orange",
// for every %c you can add more styles with ","
"Additional unformatted message"
);
Outputs:
đĄ More info here.
Selectors
Lately, some really awesome new selectors have been added to the CSS spec.
The 3 most popular and exciting are:
-
[is:](https://developer.mozilla.org/en-US/docs/Web/CSS/:is)
- Steve went into detail about this here. -
[where:](https://developer.mozilla.org/en-US/docs/Web/CSS/:where)
- is heavily used in Tailwindâs typography plugin to achieve formatting of almost any HTML and can be useful to select multiple children inside a parent selector. -
[has:](https://developer.mozilla.org/en-US/docs/Web/CSS/:has)
- A highly anticipated selector function that can be used as the elusive parent selector. Weâre still waiting for Firefox on this one.
Other than the latest and greatest, itâs useful to remember some more handy selectors such as the attribute selector, nth-child
, being able to group selectors with â,
", and understand decedent combinators.
MDN features many more to add to your repertoire.
Just remember that there could be a performance cost to the selectors you choose to use.
Some more points to remember
-
100vh
is not really all the viewport on mobile. When the new viewport units get support, that will be the way. - Youâre probably gonna need JavaScript for animations as weâve seen in some of the animation examples. For a clean API and great perf with a small bundle check out Motion One (the vanilla JS equivalent to Reacts Framer-Motion, fun fact: they were written by the same person).
- If you get good with CSS you can create awesome stuff like these hovering cards below, which are nothing more than highly crafted CSS by someone who knows their stuff.
Conclusion
Knowing CSS well is a super power. From my experience, when you get stuck with CSS, itâs much more time consuming than a JavaScript bug.
Thereâs always way more to learn and understand deeply, and if you do find the time, I suggest you focus on the fundamentals. The new stuff can wait.
I hope something form all these tricks stuck with you and you might hav learned something new.
If you do want to keep up with some great resources and blogs that cover CSS, here are some that Iâve enjoyed:
- CSS Tricks
- Josh W Commeauâs blog
- Ahmad Shadeedâs blog
- Lea Verou
- Adam Argyle
- Tom digging deep into flexbox properties
About me
Hi! Iâm Yoav, I do DevRel and Developer Experience at Builder.io.
We make a way to drag + drop with your components to create pages and other CMS content on your site or app, visually.
You can read more about how this can improve your workflow here.
You may find it interesting or useful, head on to Builder.io for more info.