Eight CSS Tips for Advanced Layouts and Effects

2017-07-03 11 min read GuestPost

The realm of web front-end development has made considerable progress over the last few years. However, the web front-end, as the users see it, is still the same: HTML markup styled with CSS.

Many layout problems can seem simple at first but often proves to be tricky. Without extensive knowledge of how certain CSS features work, these advanced layouts can seem impossible to achieve with CSS alone.

Eight Expert CSS Tips

In this article, you will find eight expert CSS tips and tricks that leverage lesser known CSS features to implement some of these advanced layouts and effects.

1. Maximizing CSS Sibling Selectors

The problem: You are losing optimization opportunities by not using sibling selectors.

The solution: Use sibling selectors whenever it makes sense. Whenever you are working with a list of items, and you need to treat the first or the last item differently, your first instinct may be to use the

  <td>
    <div class="text codecolorer">
      :first-child
    </div>
  </td>
</tr>
1

and

  <td>
    <div class="text codecolorer">
      :last-child
    </div>
  </td>
</tr>
1

pseudo CSS selectors.

For example, when creating a CSS-only hamburger menu icon:

This makes sense: Each bar has a margin-bottom, except for the last one.

Yet the same effect is also possible through the adjacent sibling selector (+):

This also makes sense: Everything after the first bar has a margin-top. Not only does this CSS trick save a few extra bytes (which can easily add up for any medium-sized project), but it also opens up a world of possibilities.

Consider this list of cards:

Each one has a title and text, the latter of which is hidden by default. If you want to make only the text of the active card (with the

  <td>
    <div class="text codecolorer">
      .active
    </div>
  </td>
</tr>
1

class) and the ones following it visible you can do it quickly using just CSS:

With a little JavaScript, this can be interactive as well.

Relying on JavaScript alone for all that, however, would result in a script like this:

where including jQuery as a dependency lets you have somewhat short code.

2. Consistent HTML Element Sizing

The problem: HTML elements have inconsistent sizes across different browsers.

The solution: Set

  <td>
    <div class="text codecolorer">
      box-sizing
    </div>
  </td>
</tr>
1

for all elements to

  <td>
    <div class="text codecolorer">
      border-box
    </div>
  </td>
</tr>
1

. A long-time bane for web developers, Internet Explorer did one thing right: It sized boxes properly.

Other browsers only look at the content when calculating the width of an HTML element, with everything else treated as surplus. A

  <td>
    <div class="text codecolorer">
      width: 200px
    </div>
  </td>
</tr>
1

div, with

  <td>
    <div class="text codecolorer">
      20px
    </div>
  </td>
</tr>
1

padding and a

  <td>
    <div class="text codecolorer">
      2px
    </div>
  </td>
</tr>
1

border, renders as 242 pixels wide.

Internet Explorer considers padding and border as a part of the width. Here, the div from above would be 200 pixels wide.

Once you get the hang of it, you will find the latter approach to be more logical, even if it doesn’t follow standards.

If I say the width is 200px, gosh darn it, it’s gonna be a 200px wide box even if I have 20px of padding.

In any case, the following CSS keeps element sizes (and therefore layouts) consistent across all browsers:

The second set of CSS selectors protects HTML elements styled without border-box in mind from layout disruption.

  <td>
    <div class="text codecolorer">
      box-sizing: border-box
    </div>
  </td>
</tr>
1

is so useful that it’s part of a relatively popular CSS framework called sanitize.css.

3. Dynamic Height Elements

The problem: Keeping an HTML element’s height proportional to its width.

The solution: Use vertical padding as a replacement for height.

Let’s say you want an HTML element’s height to always match its CSS width.

  <td>
    <div class="text codecolorer">
      height: 100%
    </div>
  </td>
</tr>
1

doesn’t change the default behavior of elements matching the height of its content.

The answer is to set the height to 0 and use padding-top or padding-bottom to set

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

’s actual height instead. Either property can be a percentage of the element’s width:

Now

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

will remain a square no matter how wide it becomes.

  <td>
    <div class="text codecolorer">
      overflow: hidden
    </div>
  </td>
</tr>
1

keeps long content from breaking this ratio.

This technique, with some modification, is great for creating video embeds that retain their aspect ratio at any size. Just align the embed with

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

’s top and left through

  <td>
    <div class="text codecolorer">
      position: absolute
    </div>
  </td>
</tr>
1

, set both dimensions of the embed to 100% so that it “fills up”

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

, and change

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

’s

  <td>
    <div class="text codecolorer">
      padding-bottom
    </div>
  </td>
</tr>
1

to match the video’s aspect ratio.

  <td>
    <div class="text codecolorer">
      position: relative
    </div>
  </td>
</tr>
1

for

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

ensures that the

  <td>
    <div class="text codecolorer">
      iframe
    </div>
  </td>
</tr>
1

absolute positioning works properly. The new

  <td>
    <div class="text codecolorer">
      padding-bottom
    </div>
  </td>
</tr>
1

is just the aspect ratio’s height divided by its width, times 100. For example, if the aspect ratio of the video embed is 16:9, the padding-bottom percentage should be 9 divided by 16 (.5625) and multiplied by 100 (56.25).

4. Dynamic Width Elements

The problem: Keeping an HTML element’s width proportional to its height.

The solution: Use font-size as the basis for the element’s dimensions.

Now, what about the reverse, or containers that change width as their height does? This time, it’s

  <td>
    <div class="text codecolorer">
      font-size
    </div>
  </td>
</tr>
1

to the rescue. Remember that width and height can be in

  <td>
    <div class="text codecolorer">
      em
    </div>
  </td>
</tr>
1

s, meaning they can be a ratio of the element’s

  <td>
    <div class="text codecolorer">
      font-size
    </div>
  </td>
</tr>
1

.

An element with a

  <td>
    <div class="text codecolorer">
      font-size
    </div>
  </td>
</tr>
1

of 40px, a width of

  <td>
    <div class="text codecolorer">
      2em
    </div>
  </td>
</tr>
1

, and a height of

  <td>
    <div class="text codecolorer">
      1em
    </div>
  </td>
</tr>
1

would be 80 pixels (40 x 2) wide and 40 pixels (40 x 1) tall.

Want to change

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

’s height? Change font-size.

The only caveat is that it’s impossible to make an element’s font-size match the height of its parent automatically through only CSS. Yet this technique allows a Javascript resize script to be cut down from:

1
2
3
<span class="hljs-keyword">var</span> container = document.querySelector( <span class="hljs-string">'.container'</span> );
container.style.height = yourDesiredHeight + <span class="hljs-string">'px'</span>;
container.style.width = yourDesiredHeight * yourDesiredRatio + <span class="hljs-string">'px'</span>;

to:

1
document.querySelector( <span class="hljs-string">'.container'</span> ).style.fontSize = yourDesiredHeight + <span class="hljs-string">'px'</span>;

5. Vertical Centering of Dynamic Content

The problem: Keeping an HTML element (with unknown height) vertically centered inside another.

The solution: Set the outer element to

  <td>
    <div class="text codecolorer">
      display: table
    </div>
  </td>
</tr>
1

, then convert the inner element into a CSS

  <td>
    <div class="text codecolorer">
      table-cell
    </div>
  </td>
</tr>
1

. Or just use CSS Flexbox.

It’s possible to vertically center one line of text with

  <td>
    <div class="text codecolorer">
      line-height
    </div>
  </td>
</tr>
1

:

For multiple lines of text or non-text content, CSS tables are the answer. Set

  <td>
    <div class="text codecolorer">
      .container
    </div>
  </td>
</tr>
1

’s display to

  <td>
    <div class="text codecolorer">
      table
    </div>
  </td>
</tr>
1

, then use

  <td>
    <div class="text codecolorer">
      display: table-cell
    </div>
  </td>
</tr>
1

and

  <td>
    <div class="text codecolorer">
      vertical-align: middle
    </div>
  </td>
</tr>
1

for

  <td>
    <div class="text codecolorer">
      .text
    </div>
  </td>
</tr>
1

:

Think of this CSS trick as the vertical equivalent of

  <td>
    <div class="text codecolorer">
      margin: 0 auto
    </div>
  </td>
</tr>
1

. CSS3’s Flexbox is a great alternative for this technique if Internet Explorer’s buggy support is acceptable:

6. Same-Height Columns

The problem: Keeping columns the same height.

The solution: For each column, use a large negative

  <td>
    <div class="text codecolorer">
      margin-bottom
    </div>
  </td>
</tr>
1

value, and cancel that out with an equally large

  <td>
    <div class="text codecolorer">
      padding-bottom
    </div>
  </td>
</tr>
1

. CSS tables and Flexbox also work.

Using

  <td>
    <div class="text codecolorer">
      float
    </div>
  </td>
</tr>
1

or

  <td>
    <div class="text codecolorer">
      display: inline-block
    </div>
  </td>
</tr>
1

, it’s possible to create side-by-side columns through CSS.

Note the use of

  <td>
    <div class="text codecolorer">
      box-sizing: border-box
    </div>
  </td>
</tr>
1

to properly size the

  <td>
    <div class="text codecolorer">
      .cols
    </div>
  </td>
</tr>
1

. See Consistent HTML Element Sizing above.

The borders of the first and last column don’t go all the way down; they don’t match the height of the taller second column. To fix this, just add

  <td>
    <div class="text codecolorer">
      overflow: hidden
    </div>
  </td>
</tr>
1

to

  <td>
    <div class="text codecolorer">
      .row
    </div>
  </td>
</tr>
1

. Then set each

  <td>
    <div class="text codecolorer">
      .col
    </div>
  </td>
</tr>
1

’s

  <td>
    <div class="text codecolorer">
      margin-bottom
    </div>
  </td>
</tr>
1

to 99999px and its

  <td>
    <div class="text codecolorer">
      padding-bottom
    </div>
  </td>
</tr>
1

to 100009px (99999px + the 10px padding applied to

  <td>
    <div class="text codecolorer">
      .col
    </div>
  </td>
</tr>
1

’s other sides).

A more straightforward alternative is Flexbox. Again, only use this if Internet Explorer support isn’t a must.

One more alternative with better browser support: CSS tables (without

  <td>
    <div class="text codecolorer">
      vertical-align: middle
    </div>
  </td>
</tr>
1

).

7. Going Beyond the Box

The problem: Boxes and straight lines are so clichéd.

The solution: Use

  <td>
    <div class="text codecolorer">
      transform: rotate(x)
    </div>
  </td>
</tr>
1

, or

  <td>
    <div class="text codecolorer">
      border-radius
    </div>
  </td>
</tr>
1

.

Take a typical series of panes from a marketing or brochure website: a vertical stack of slides with a singular point. Its markup and CSS could look something like this:

At the cost of making the markup much more complicated, these boxy panes could be turned into a stack of parallelograms.

There’s a lot going on here:

The height of each pane is controlled by .pane-container. The negative margin-bottom makes sure the panes stack up snugly.

  •   <td>
        <div class="text codecolorer">
          .pane-background
        </div>
      </td>
    </tr>
    
    1

    , its child

      <td>
        <div class="text codecolorer">
          .mask-box
        </div>
      </td>
    </tr>
    
    1

    , and its grandchild

      <td>
        <div class="text codecolorer">
          .image
        </div>
      </td>
    </tr>
    
    1

    are all set to

      <td>
        <div class="text codecolorer">
          position: absolute
        </div>
      </td>
    </tr>
    
    1

    . Each element has different

      <td>
        <div class="text codecolorer">
          top
        </div>
      </td>
    </tr>
    
    1

    ,

      <td>
        <div class="text codecolorer">
          left
        </div>
      </td>
    </tr>
    
    1

    ,

      <td>
        <div class="text codecolorer">
          bottom
        </div>
      </td>
    </tr>
    
    1

    , and

      <td>
        <div class="text codecolorer">
          right
        </div>
      </td>
    </tr>
    
    1

    values. This eliminates any spacing created by the rotations detailed below.

    •   <td>
          <div class="text codecolorer">
            .mask-box
          </div>
        </td>
      </tr>
      
      1

      is rotated 2 degrees (counter-clockwise).

      •   <td>
            <div class="text codecolorer">
              .image
            </div>
          </td>
        </tr>
        
        1

        is rotated -2 degrees to counteract

          <td>
            <div class="text codecolorer">
              .mask-box
            </div>
          </td>
        </tr>
        
        1

        ’s rotation.

        •   <td>
              <div class="text codecolorer">
                .mask-box
              </div>
            </td>
          </tr>
          
          1

          ’s overflow is hidden so that its rotated top and bottom sides clip the

            <td>
              <div class="text codecolorer">
                .image
              </div>
            </td>
          </tr>
          
          1

          element.

        Feel free to play around with this codepen. Try using lower rotate values and see what happens.

        On a related note, turning an image into a circle or oval is dead simple. Just apply

          <td>
            <div class="text codecolorer">
              border-radius: 100%
            </div>
          </td>
        </tr>
        
        1

        to the

          <td>
            <div class="text codecolorer">
              img
            </div>
          </td>
        </tr>
        
        1

        element.

        Real-time CSS modifications such as these lessen the need to prepare content before it’s published on a website. Instead of applying a circle mask to a photo in Photoshop, the web developer can just apply the same effect through CSS without changing the original photo.

        The additional advantage is that by leaving the content untouched and not reliant on the website’s current design, future redesigns or revamps are facilitated.

        8. Night Mode

        The problem: Implementing a night mode without creating a new stylesheet.

        The solution: Use CSS filters.

        Some apps feature a night mode, where the interface darkens for better readability under low light. On newer browsers, CSS filters can create the same effect, by applying Photoshop-like effects.

        A useful CSS filter is

          <td>
            <div class="text codecolorer">
              invert
            </div>
          </td>
        </tr>
        
        1

        , which (no surprise) inverts the colors of everything inside an element. This makes creating and applying a new set of styles unnecessary.

        Using this filter on black text and a white background simulates night mode.

          <td>
            <div class="text codecolorer">
              !important
            </div>
          </td>
        </tr>
        
        1

        ensures that these new colors override any existing styles.

        Unfortunately, the image looks weird, because its colors were inverted with everything else. The good news is that multiple filters can apply at the same time. Adding the hue-rotate filter switches images and other visual content back to normal:

        Why does this work?

          <td>
            <div class="text codecolorer">
              hue-rotate(180deg)
            </div>
          </td>
        </tr>
        
        1

        just creates the same effect as

          <td>
            <div class="text codecolorer">
              invert(1)
            </div>
          </td>
        </tr>
        
        1

        did. Here’s a demo of how night-mode CSS would work when toggled through a JavaScript-powered button.

        Make the Most out of CSS

        Unless the browser or how websites are built changes dramatically in the future, a good knowledge of CSS will remain a fundamental skill in the web development space.

        All of these CSS tips share something in common: They maximize the use of CSS as a styling language, letting the browser itself do the heavy lifting. And, when done right, this will always yield better results, better performance, and hence a better user experience.

        Let us know if you have any CSS trick that you find interesting and useful in the comments section below.

        This article is originally posted in Toptal.

comments powered by Disqus