DEV Community

Cover image for How to add curves to your website
Dzhavat Ushev
Dzhavat Ushev

Posted on • Updated on • Originally published at dzhavat.github.io

How to add curves to your website

This post was originally published on my blog.


As front-end developers we’re usually the ones responsible for translating a design into code. And sometimes the designer wants to try something creative that breaks out of the rectangular shapes we’re so used to. So he/she decides to add some curves. It’s our job now to do magic and make them appear on the page.

A couple of weeks ago I got a design that roughly resembled this one:

Example mockup


Example mockup (excuse my basic Photopea skills)

In this post I’m going to show you how to add curves to the top and bottom of an element. I’m going share my solution. You might have a different one. That’s fine! If you do, let me know in the comments below.

Before writing any code

It’s important to spend a bit of time thinking about the design. Try to come up with a strategy for how you’re going to approach it. What challenges are you possibly going to face? How will it look on mobile? On desktop? On wide screens? Can you make it flexible and reusable in other places? Are the techniques you want to use well supported or should you consider having a fallback?

Let’s briefly analyze the current task:

  • The mockup can be divided in three parts - top curve, content, bottom curve. The top and bottom curves are purely for decoration. In case something happens and they don’t appear, the main content element should end up with straight lines. Nothing else should break.
  • Looking at the curves more closely, I can see that they are in fact the same. The only difference is that one of them is flipped vertically. This helps me a lot here because I can export the curve only once and reuse it in both top and the bottom. We’ll see how in a bit.

Top and bottom curves


Top and bottom curves

  • On wider screens the curves must go from edge-to-edge while the content can be centered.

Nice! Now let’s look at some code.

Adding the main content

This one is pretty straightforward and you’ve probably done it many times already. There’s a wrapper .container that goes full width and can be used for setting a background color and adding the curves. The .tabs-container is used for holding the content. This element will be centered on wider screens.

<div class="container">
  <div class="tabs-container">
    <!-- Some content here -->
  </div>
</div>
.container {
  background-color: #026b96;
}

.tabs-container {
  color: white;
  padding: 1.5rem;
}

@media (min-width: 980px) {
  .tabs-container {
    margin-left: auto;
    margin-right: auto;
    padding: 3rem 2rem;
    width: 800px;
  }
}

Here’s the result so far (CodePen):

Step 1


Step 1

That’s a good baseline for now. Even if I don’t add the curves, everything still looks fine.

Adding the top curve

I already said that the curves are there only for decoration and making the element look more organic. So instead of adding them as img elements, which I’ve seen out in the wild, I’m going to add them using ::before and ::after pseudo elements. In order to have a curve that goes edge-to-edge on wider screens, I’ve exported it as a 3000x103px SVG image. This will still cause issues on super wide screens but it’s enough to illustrate the purpose of this post.

What is left now is adding the curve to the element:

.container {
  /* ... */
  position: relative;
}

.container::before {
  background: url("path/to/curve.svg") center bottom no-repeat;
  bottom: 100%;
  content: '';
  height: 103px;
  position: absolute;
  width: 100%;
}

There are a couple of points here:

  • Because the ::before element has position: absolute it’s a good idea to set the position: relative on the .container. This will make the ::before element stay inside the .container and thus becomes easier to move around.
  • The background declaration is interesting. There are a few things but the positioning (defined by center bottom) is the key. This specifies where to place the image relative to edges of the element. center will center the image on the x-axis, while bottom will place it on the bottom of the y-axis. You can play with different combinations. left bottom or right bottom are also valid. You can specify background-size as well. Try it and see the effect.
  • The content: '' is quite important. Without it the element will not be generated.
  • height: 103px is the height of the SVG image. In your case that number might be different.
  • bottom: 100% places the bottom edge of the element at the top edge of the .container. This is achieved by using a percentage value which is relative to the container’s height. Thanks to Andrew Bone for sharing this tip.

Here’s the result so far (CodePen):

Step 2


Step 2

Adding the bottom curve

Time for the final part. This is going to be fun.

I already said in the beginning that the bottom curve is the same as the top. The difference is that the bottom one is flipped. Luckily there’s a CSS property that can help us achieve that. Let’s have a look.

.container::before,
.container::after {
  background: url("path/to/curve.svg") center bottom no-repeat;
  content: '';
  height: 103px;
  position: absolute;
  width: 100%;
}

.container::before {
  bottom: 100%;
}

.container::after {
  top: 100%;
  transform: rotateX(180deg);
}

Much of the code from the previous step is repeated here as well. I’ve put all common declarations between the ::before and ::after elements together. That way I can make adjustments in only one place.

The most important code here is the transform property in the ::after element.

Using the rotateX() function I can rotate the image along its horizontal axis. This feels intuitive because the value is an angle and specifying 180deg as a value will flip it.

Note: In a previous version of this code I used scaleY(-1) to achieve the same thing. This works as well but, as Andrew Bone points out, rotateX() is more readable and easier to understand.

There’s one weird thing worth mentioning here. You might’ve noticed that the background image of the ::after element is set to center bottom. This is kinda strange because one would think the correct positioning should be center top since we move the element down but want to place its background image as close to the top as possible. center bottom is actually correct in this case because the element is flipped (remember rotateX(180deg)?), so its bottom is now on the top. You can observe this by setting the height and bottom to say 150px so the element is bigger than its background image.

Here’s the final result (CodePen):

Final result


Final result

That’s it! Now you know how to add curves or other weird shapes to your website. Now go and get creative! Here are a couple of examples I found for inspiration.

Firefox Developer Edition (link)

Firefox Developer Edition


Firefox Developer Edition

Atlassian (link)

Atlassian


Atlassian

Do you have other techniques for adding curves/shapes? Let me know in the comments below.

Discussion (3)

Collapse
link2twenty profile image
Andrew Bone

This is a really nice effect, there are a couple of things I'd have done a little differently but with the same result 🙂

For your positioning, it might be better to use 100%.

.container::before,
.container::after {
  background: url("path/to/curve.svg") center bottom no-repeat;
  content: '';
  height: 103px;
  position: absolute;
  width: 100%;
}

.container::before {
  bottom: 100%;
}

.container::after {
  top: 100%;
  transform: scaleY(-1);
}

This has the same result but without the need for any hardcoded numbers.

Also, and this is just my personal style/preference, I'd replace transform: scaleY(-1); with transform: rotateX(180deg); for readability.

Collapse
dzhavat profile image
Dzhavat Ushev Author

Moving the ::before with bottom: 100% and ::after with top: 100% is quite smart! Way better than those hardcoded values. Thanks for your tips!

Collapse
dzhavat profile image
Dzhavat Ushev Author

Thanks again for your tips. I've updated the article to include your suggestions. :)