loading...
Cover image for CSS Battle #10 - Cloaked Spirits

CSS Battle #10 - Cloaked Spirits

pheeria profile image Olzhas Askar ・6 min read

Times don't get no better, boys. The number ten is a special one. It is the first two-digit number. It is a famous football shirt number. In fact, it is so famous, that Turks would call something on numara, number ten, in order to express admiration. As for the challenge, it is going to be fun.

1. Div Way

Let's start with defining what we'll need. Three columns, squeezed together, with circle shapes on top. So, we'll make three divisions, having one another division inside each of them. In order to differentiate them from each other let's call the outer div column and the inner one circle. Here is the markup.

<div class="column">
    <div class="circle"></div>
</div>
<div class="column">
    <div class="circle"></div>
</div>
<div class="column">
    <div class="circle"></div>
</div>

All of this needs to be on a purple background. In order to create a frame for our shapes, let's restrict them by styling body tag. Note, that I am using a zero-padding and font-size: 0. And because of declaring padding we can't use * selector.

body {
  padding: 42px 30px 30px 42px;
  font-size: 0;
  background: #62306d;
}

Then we switch to the columns. A column should have a width of 100px, a height of 150px, inline-block display obviously, otherwise, why would we be setting the font size to zero? All this on a nice yellow background with circled borders.

.column {
  width: 100px;
  height: 150px;
  display: inline-block;
  background: #f7ec7d;
  border-radius: 50px 50px 0 0;
}

The code above doesn't work quite yet, because there is always an exception to a rule. The middle shape is almost like showing us a middle finger, it needs some special treatment. It's funny how :nth-child() is not zero-indexed. Nonetheless, we adjust the height, effectively pushing the side columns down.

.column:nth-child(2) {
  height: 250px;
}

Inside of each column, we already have a division defined to represent a circle. We set width and height to the same sixty pixels and border-radius to fifty percent to get a circle. We add a border of twenty pixels and background color.

.circle {
  width: 60px;
  height: 60px;
  border: 20px solid #aa445f;
  background: #e38f66;
  border-radius: 50%;
}

Our special snowflake, the middle column, needs to be adjusted again. This time we change the background and the border color.

.column:nth-child(2) .circle {
  background: #aa445f;
  border-color: #e38f66;
}

In case you didn't know, a border color and box-shadow default to the color attribute of an element, if omitted. So, we could rewrite our colors in the following manner.

.circle {
  width: 60px;
  height: 60px;
  border: 20px solid;
  border-radius: 50%;
  color: #aa445f;
  background: #e38f66;
}
.column:nth-child(2) .circle {
  color: #e38f66;
  background: #aa445f;
}

So, this is it. You can start playing around with CSS to see how breaking things results in unexpected shapes. For example, try removing a height for columns or border for circles. Isn't it fun? Here you go with the full solution.

<div class="column"><div class="circle"></div></div>
<div class="column"><div class="circle"></div></div>
<div class="column"><div class="circle"></div></div>

<style>
  body {
    padding: 42px 30px 30px 42px;
    font-size: 0;
    background: #62306D;
  }
  .column {
    width: 100px;
    height: 150px;
    display: inline-block;
    background: #F7EC7D;
    border-radius: 50px 50px 0 0;
  }
  .column:nth-child(2) {
    height: 250px;
  }
  .circle {
    width: 60px;
    height: 60px;
    border: 20px solid #AA445F;
    background: #E38F66;
    border-radius: 50%;
  }
  .column:nth-child(2) .circle {
    background: #AA445F;
    border-color: #E38F66;
  }
</style>

2. Pseudo Way

Can we do it another way? Sure, we can. But before we do that, do you know what this (_>_) means? A nice smiley, isn't it? What if I showed you it in another context?

val ordered = seq.sort(_>_)

It means, sort by ascending. Scala has some very unusual symbols for a developer with a background of C-like languages.
Do you what this * + * means? Clearly, it is an owl. An owl selector. After reading about it on Every Layout, I got fascinated by this simple, yet powerful idea - elements position should not be its own concern, rather its parent's. Previously, an owl selector would be used to solve this problem in an elegant way. Now we have a flexible box. Let's see how our solution would look like.

We still have three columns, but this time let's use paragraphs instead of divisions. It's semantically incorrect, I know, but you shouldn't be using CSS for drawing figures either. We choose p because of it's display: block property. To the middle element, we give an id to differentiate it from the rear ones. Notice how we don't need quotes if our attribute's value consists of a single word. Here is the markup.

<p></p>
<p id=a></p>
<p></p>

To style a column we can reuse the same code from our previous solution. There are two differences, though. I used viewport height and viewport width as measurement units to be a little bit more soft coded, that is to allow some adaptiveness. And we also don't need display: inline-block.

p {
  width: 25vw;
  height: 50vh;
  background: #f7ec7d;
  border-radius: 12.5vw 12.5vw 0 0;
}

Our middle ~finger~ column is restyled when it comes to height. We select it by targeting a paragraph which has an id attribute defined.

p[id] {
  height: 62.5vw;
}

To recreate the circles, let's use pseudo-classes this time. All the same code from above, except for the addition of content: "" and display: block to make our sizing work. And of course, we overwrite background and border colors for the central column.

p:after {
  content: "";
  display: block;
  width: 20vh;
  height: 20vh;
  border: 5vw solid #aa445f;
  background: #e38f66;
  border-radius: 50%;
}
p[id]:after {
  background: #aa445f;
  border-color: #e38f66;
}

Now we should see a white background with two columns on the left side. This is not what we want. But this is what we get, for we haven't done any placement of our elements. Here comes the missing piece.

body {
  height: calc(100vh + 8px);
  background: #62306d;
  display: flex;
  justify-content: center;
  align-items: flex-end;
}

We specify a flex display, justify horizontally all columns to be in the center and align our items to the bottom of the screen. If you know why I had to add eight pixels to the whole height, and that's the only way I found so far to work, please let me know. I am curious as well.

So, here comes the whole solution.

<p></p>
<p id=a></p>
<p></p>

<style>
body {
  height: calc(100vh + 8px);
  background: #62306d;
  display: flex;
  justify-content: center;
  align-items: flex-end;
}
p {
  width: 25vw;
  height: 50vh;
  background: #f7ec7d;
  border-radius: 12.5vw 12.5vw 0 0;
}
p[id] {
  height: 62.5vw;
}
p:after {
  content: "";
  display: block;
  width: 20vh;
  height: 20vh;
  border: 5vw solid #aa445f;
  background: #e38f66;
  border-radius: 50%;
}
p[id]:after {
  background: #aa445f;
  border-color: #e38f66;
}
</style>

3. Shadow Way

I've already mentioned, that if there is one thing I learned by solving these challenges then it would box-shadow. I will try to apply it here as well.

Caution! Do not try to repeat this in production!

The idea is to position three divs absolutely in relation to the whole page. Divs are named l for left, c for center and r for right.

<div id=l></div><div id=c></div><div id=r></div>

These divs are going to be representing circles. They have the same width and height, background and border, everything like above. What makes the difference are position: fixed and specified top: 134px and left: 50px parameters.

div {
  position: fixed;
  top: 134px;
  left: 50px;
  width: 20vh;
  height: 20vh;
  background: #e38f66;
  border: 5vw solid #aa445f;
  border-radius: 50%;
}

We adjust the placement and colors for the central and right elements a bit.

#c {
  top: 34px;
  left: 150px;
  background: #aa445f;
  border-color: #e38f66;
}
#r {
  left: 250px;
}

Then we give colors to our body.

* {
  background: #62306d;
  color: #f7ec7d;
}

You may wonder, why do we use color property? After all, we don't have any text here. The color property is taken as a default value for borders and shadows, that's why.
And here comes the jewel of the solution, the mighty box-shadow.

box-shadow: 0 10px, 0 20px, 0 30px, 0 40px, 0 50px, 0 60px, 0 70px, 0 80px,
  0 90px, 0 100px, 0 105px, 0 110px, 0 120px, 0 130px, 0 135px 0 5px, 0 190px 0
    30px;

Just pile down a circle after circle after circle all the way down to the bottom. Initially, a ten-pixel distance is enough, but when the level of the left and right circles is reached, we will see a thin line, where the columns don't touch. So we make our last two circles bigger to cover the flaw.

Here is the whole solution.

<div id=l></div><div id=c></div><div id=r></div>

<style>
* {
  background: #62306d;
  color: #F7EC7D;
}
div {
  position: fixed;
  top: 134px;
  left: 50px;
  width: 20vh;
  height: 20vh;
  background: #e38f66;
  border: 5vw solid #aa445f;
  border-radius: 50%;
  box-shadow:0 10px, 0 20px, 0 30px, 0 40px, 0 50px, 0 60px, 0 70px, 0 80px, 0 90px, 0 100px, 0 105px, 0 110px, 0 120px, 0 130px, 0 135px 0 5px, 0 190px 0 30px;
}
#c {
  top: 34px;
  left: 150px;
  background: #aa445f;
  border-color: #e38f66;
}
#r {
  left: 250px;
}
</style>

Writing this took a lot of time. I hope you like it. Have a nice day!

Posted on by:

pheeria profile

Olzhas Askar

@pheeria

I want to be able to make things look beautiful.

Discussion

markdown guide