CSS Tips for Better Web Development

Yoav Ganbar - Feb 23 '23 - - Dev Community

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:

  1. Using position: sticky;
/* The Essential bit  */

header {
  position: sticky;
  top: 0;
}

footer {
  position: sticky;
  bottom: 0;
}
Enter fullscreen mode Exit fullscreen mode

  1. 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;
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
/* 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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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:

  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.
/* 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;
}
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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:

  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:

<button class="fill">Fill In</button> 
Enter fullscreen mode Exit fullscreen mode

.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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
.parent {
  position: relative;
}

.child {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
.parent {
 display: grid;
 place-content: center;
}
Enter fullscreen mode Exit fullscreen mode

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 get 16 / 9 or 3 / 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: '';
}
Enter fullscreen mode Exit fullscreen mode

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%);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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"
);
Enter fullscreen mode Exit fullscreen mode

Outputs:

a screenshot of a console output with CSS.

// 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"
);
Enter fullscreen mode Exit fullscreen mode

Outputs:

a screenshot of a console output with CSS.

💡 More info here.

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.
  2. [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.
  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, 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:

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player