CSS Tips for Better Web Development
Tags: webdev, css, design
Published: 2023-02-23 15:25:25

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](https://www.tiktok.com/@steve8708/video/7103578583502818602) a while ago about this. 

<aside>
💡 Learn more about it on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap/Basic_concepts).
</aside>

Here’s a demo showing how to do it on either the `x-axis` or `y-axis`:

{% codepen https://codepen.io/hamatoyogi/pen/BaPgNjP  %}

## 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:

1. **Using `position: sticky;`**

```css
/* The Essential bit  */

header {
  position: sticky;
  top: 0;
}

footer {
  position: sticky;
  bottom: 0;
}
```

{% codepen https://codepen.io/hamatoyogi/pen/mdjYLwR %}

2. **With CSS Grid:**

```css
/* 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;
}
```

{% codepen https://codepen.io/hamatoyogi/pen/WNKBzLO %}

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](https://www.tiktok.com/@tomisloading/video/7150356937471905070?_r=1&_t=8ZhTna1rxQY) to understand and implement.

```html
<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>
```

```css
/* 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;
}
```

{% codepen https://codepen.io/hamatoyogi/pen/NWBVENG %}

## Animation with CSS Custom properties

There are some [caveats to using CSS vars in your design systems](https://blog.nucleus.design/be-aware-of-css-custom-properties/). But overall, they have been a game changer in web development.

Defining a variable is pretty straightforward, and is done like this:

```css
: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](https://natemoo.re/posts/complex-animations).

In the demo below, the secret ingredient is threefold:

1. `animation-delay` with a negative value, causes the animation to start immediately.
2. `animation-play-state` set to paused initially, to only start when we want/need to.
3. The `--progress` custom property to allow control over the animation.

```css
/* 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:

```javascript
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}`);
});
```

{% codepen https://codepen.io/hamatoyogi/pen/bGjyQop %}

This is another demo that shows this method in practice, but in parallax style with a JS scroll listener:

{% codepen https://codepen.io/scottkellum/pen/WWeXab %}
 
### Hover effects with `box-shadow`

There are a few keys to this trick:
1. `box-shadow` values are: `[inset?] [top] [left] [blur] [size] [color]`;
2. To get a solid fill, `blur` should be `0`
3. Using `inset` allows to “fill” our element
4. Negative values flip `top` / `left` to `bottom` / `right` and vice versa
5. Multiple shadows can be stacked
6. 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:

```html
<button class="fill">Fill In</button> 
```
```css

.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:

{% codepen https://codepen.io/giana/pen/BZaGyP %}

### Fixing nested border-radius with calculations

[Syntax.FM’s](https://syntax.fm/) [Wes Bos](https://wesbos.com/) has been doing some great videos over on TikTok. [In one of his vids](https://www.tiktok.com/@wesbos/video/7179258920723057925), he fixed Twitter’s new profile pics border radius for nested elements with this nifty trick:

```css
.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);
}
```

{% twitter https://twitter.com/builderio/status/1532129790999859200 %}

## Centering an element both horizontally and vertically

Funny enough, this is still one of the most popular questions on [stack overflow](https://stackoverflow.com/questions/19461521/how-to-center-an-element-horizontally-and-vertically). Even [Dan Abramov](https://twitter.com/dan_abramov) struggled with this in his [mock interview with Ben Awad](https://youtu.be/XEt09iK8IXs?t=637).

### The old way

Before the introduction of `flex-box` the way to achieve this was by using absolute positioning.

The general trick is so:
```html
<div class="parent">
  <div class="child">Center me</div>
</div>
```
```css
.parent {
  position: relative;
}

.child {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
```

{% codepen https://codepen.io/hamatoyogi/pen/poZmPGb %}

### 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](https://developer.mozilla.org/en-US/docs/Web/CSS/Layout_cookbook/Center_an_element).

```html
<div class="parent">
  <div class="child">Center me</div>
</div>
```
```css
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}
```

{% codepen https://codepen.io/hamatoyogi/pen/bGjyaRL %}

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.

```html
<div class="parent">
  <div class="child">Center me</div>
</div>
```
```css
.parent {
 display: grid;
 place-content: center;
}
```

{% codepen https://codepen.io/hamatoyogi/pen/mdjYpNp %}

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](https://caniuse.com/css-grid) 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](https://webflow.com/blog/neumorphism).

> Check out the [documentation for backdrop-filter](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter) to learn more.

{% codepen https://codepen.io/robinrendle/pen/LmzLEL %}

## Handling image styles

Images on the web [have come a long way](https://www.builder.io/blog/fast-images), but a few good properties are a must-know:

- [`object-fit`](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) - helps with not stretching out images, as [seen here](https://www.tiktok.com/@wesbos/video/7172230217862352133).
- `[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 get `16 / 9` or `3 / 4` boxes without ye ole [padding aspect ratio hack](https://css-tricks.com/aspect-ratio-boxes/). Again, Wes Bos has [a great video](https://www.tiktok.com/@wesbos/video/7172230217862352133) showcasing this and more.

## Shapes
There are a few ways to create [shapes in CSS](https://css-tricks.com/the-shapes-of-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:

```css
#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`:
```css
#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](https://bennettfeely.com/clippy/) by [Bennett Feely](https://twitter.com/bennettfeely).

`svg` has an equivalent `<clipPath>` element that you can use for the same results, as in this demo:

{% codepen https://codepen.io/hamatoyogi/pen/NWyYYbV %}

## Debugging CSS

Knowing how to approach debugging is paramount. In fact, this tweet is what inspired this post:

{% twitter https://twitter.com/Dominus_Kelvin/status/1622173196689739777 %}

### Console.log in CSS

The key ways that came from the responses were:

```css
/* 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](https://en.wikipedia.org/wiki/Firebug_(software)). You can debug `z-index` issues with the [layers pane](https://www.notion.so/CSS-Tricks-You-Should-Know-d510518b84a74797adb7a550e84b2981). 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](https://developer.chrome.com/docs/devtools/css/reference/).

### Bonus: style your console.log

Did you know you can add CSS properties to your JavaScript `console.log`?

This is how you do it:

```js
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:

![a screenshot of a console output with CSS.](https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fc00acf467e1b400bbc2b52c9529ed0bf?format=webp&width=2000)

```jsx
// 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:

![a screenshot of a console output with CSS.](https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fb4dd84595cea46ac9bfd64e0a7600e9d?format=webp&width=2000)


> 💡 More info [here](https://developer.mozilla.org/en-US/docs/Web/API/console#:~:text=Styling%20console%20output).


## Selectors

Lately, some really awesome new selectors have been added to the CSS spec. 

The 3 most popular and exciting are:

1. `[is:](https://developer.mozilla.org/en-US/docs/Web/CSS/:is)` - Steve went into detail about this [here](https://www.builder.io/blog/css-is).
2. `[where:](https://developer.mozilla.org/en-US/docs/Web/CSS/:where)` - is heavily used in [Tailwind’s typography plugin](https://tailwindcss.com/docs/typography-plugin) to achieve formatting of almost any HTML and can be useful to [select multiple children inside a parent selector](https://www.tiktok.com/@wesbos/video/7163652821210975494).
3. `[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](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors), `nth-child`, being able to group selectors with ”`,`", and understand [decedent combinators](https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_combinator).

MDN features many more to add to your repertoire.

Just remember that there could be [a performance cost](https://www.notion.so/CSS-Tricks-You-Should-Know-d510518b84a74797adb7a550e84b2981) to the selectors you choose to use.

## Some more points to remember

- `100vh` is [not really all the viewport](https://dev.to/nirazanbasnet/dont-use-100vh-for-mobile-responsive-3o97) on mobile. When the [new viewport units](https://web.dev/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](https://motion.dev/) (the vanilla JS equivalent to [Reacts Framer-Motion](https://www.framer.com/motion/), fun fact: they were written by [the same person](https://github.com/mattgperry)).
- 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.

{% codepen https://codepen.io/hexagoncircle/pen/XWbWKwL %}

## 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](https://css-tricks.com/)
- [Josh W Commeau’s blog](https://www.joshwcomeau.com/tutorials/css/)
- [Ahmad Shadeed’s blog](https://ishadeed.com/articles/)
- [Lea Verou](https://lea.verou.me/publications/)
- [Adam Argyle](https://nerdy.dev/)
- [Tom digging deep into flexbox properties](https://www.tiktok.com/@tomisloading/video/7175175311515012395?_r=1&_t=8ZhTna1rxQY)

## About me

Hi! I’m [Yoav](https://twitter.com/hamatoyogi), I do DevRel and Developer Experience at [Builder.io](https://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](https://www.builder.io/blog/headless-cms-workflow).

You may find it interesting or useful, head on to [Builder.io](https://builder.io) for more info.