Styled-Components: CSS-in-JS Library for the Modern Web

This post was written by Jeremy Davis, JavaScript Developer for Toptal.

 

CSS was designed for documents, what the “old web” was expected to contain. The emergence of preprocessors like Sass or Less shows that the community needs more than what CSS offers. With web apps getting more and more complex over time, CSS’ limitations have become increasingly visible and difficult to mitigate.

Styled-components leverages the power of a complete programming language—JavaScript—and its scoping capabilities to help structure the code into components. This helps to avoid the common pitfalls of writing and maintaining CSS for large projects. A developer can describe a component’s style with no risk of side effects.

What’s the Problem?

One advantage of using CSS is that the style is completely decoupled from the code. This means that developers and designers can work in parallel without interfering with each other.

On the other hand, styled-components makes it easier to fall in the trap of strongly coupling style and logic. Max Stoiber explains how to avoid this. While the idea of separating logic and presentation is definitely not new, one might be tempted to take shortcuts when developing React components. For example, it’s easy to create a component for a validation button that handles the click action as well as the button’s style. It takes a bit more effort to split it in two components.

The Container/Presentational Architecture

This is a pretty simple principle. Components either define how things look, or they manage data and logic. A very important aspect of presentation components is that they should never have any dependencies. They receive props and render DOM (or children) accordingly. Containers, on the other hand, know about the data architecture (state, redux, flux, etc.) but should never be responsible for display. Dan Abramov’s article is a very good and detailed explanation of this architecture.

Remembering SMACSS

Although the Scalable and Modular Architecture for CSS is a style guide for organizing CSS, the basic concept is one that is followed, for the most part automatically, by styled-components. The idea is to separate CSS into five categories:

  • Base contains all the general rules.
  • Layout’s purpose it to define the structural properties as well as various sections of content (header, footer, sidebar, content, for instance).
  • Module contains subcategories for the various logical blocks of the UI.
  • State defines modifier classes to indicate elements’ states, e.g. field in error, disabled button.
  • Theme contains color, font, and other cosmetic aspects that may be modifiable or dependent on user preference.

Keeping this separation while using styled-components is easy. Projects usually include some kind of CSS normalization or reset. This typically falls in the Base category. You may also define general font sizing, line sizing, etc. This can be done through normal CSS (or Sass/Less), or through the 

1
injectGlobal

 function provided by styled-components.

For Layout rules, if you use a UI framework, then it will probably define container classes, or a grid system. You can easily use those classes in conjunction with your own rules in the layout components you write.

Module is automatically followed by the architecture of styled-components, since the styles are attached to components directly, rather than described in external files. Basically, each styled component that you write will be its own module. You can write your styling code without worrying about side effects.

State will be rules you define within your components as variable rules. You simply define a function to interpolate values of your CSS attributes. If using a UI framework, you might have useful classes to add to your components as well. You will probably also have CSS pseudo-selector rules (hover, focus, etc.)

The Theme can simply be interpolated within your components. It is a good idea to define your theme as a set of variables to be used throughout your application. You can even derive colors programmatically (using a library, or manually), for instance to handle contrasts and highlights. Remember that you have the full power of a programming language at your disposal!

Bring Them Together for a Solution

It is important to keep them together, for an easier navigation experience; We don’t want to organize them by type (presentation vs. logic) but rather by functionality.

Thus, we will have a folder for all the generic components (buttons and such). The others should be organized depending on the project and its functionalities. For instance, if we have user management features, we should group all the components specific to that feature.

To apply styled-components’ container/presentation architecture to a SMACSS approach, we need an extra type of component: structural. We end up with three kinds of components; styled, structural, and container. Since styled-components decorates a tag (or component), we need this third type of component to structure the DOM. In some cases, it might be possible to allow a container component to handle the structure of sub-components, but when the DOM structure becomes complex and is required for visual purposes, it’s best to separate them. A good example is a table, where the DOM typically gets quite verbose.

Example Project

Let’s build a small app that displays recipes to illustrate these principles. We can start building a Recipes component. The parent component will be a controller. It will handle the state—in this case, the list of recipes. It will also call an API function to fetch the data.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Recipes</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span></span>{
  <span class="hljs-keyword">constructor</span> (props) {
    <span class="hljs-keyword">super</span>(props);
    <span class="hljs-keyword">this</span>.state = {
      <span class="hljs-attr">recipes</span>: []
    };
  }

  componentDidMount () {
    <span class="hljs-keyword">this</span>.loadData()
  }

  loadData () {
    getRecipes().then(<span class="hljs-function"><span class="hljs-params">recipes</span> =&gt;</span> {
      <span class="hljs-keyword">this</span>.setState({recipes})
    })
  }

  render() {
    <span class="hljs-keyword">let</span> {recipes} = <span class="hljs-keyword">this</span>.state

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RecipesContainer</span> <span class="hljs-attr">recipes</span>=<span class="hljs-string">{recipes}</span> /&gt;</span>
    )
  }
}
</span>

It will render the list of recipes, but it does not (and should not) need to know how. So we render another component that gets the list of recipes and outputs DOM:


1
2
3
4
5
6
7
8
9
10
11
12
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecipesContainer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span></span>{
  render() {
    <span class="hljs-keyword">let</span> {recipes} = <span class="hljs-keyword">this</span>.props

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TilesContainer</span>&gt;</span>
        {recipes.map(recipe =&gt; (<span class="hljs-tag">&lt;<span class="hljs-name">Recipe</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{recipe.id}</span> {<span class="hljs-attr">...recipe</span>}/&gt;</span>))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">TilesContainer</span>&gt;</span>
    )
  }
}
</span>

Here, actually, we want to make a tile grid. It may be a good idea to make the actual tile layout a generic component. So if we extract that, we get a new component that looks like this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TilesContainer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
  render () {
    <span class="hljs-keyword">let</span> {children} = <span class="hljs-keyword">this</span>.props

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Tiles</span>&gt;</span>
        {
          React.Children.map(children, (child, i) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">Tile</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>&gt;</span>
              {child}
            <span class="hljs-tag">&lt;/<span class="hljs-name">Tile</span>&gt;</span>
          ))
        }
      <span class="hljs-tag">&lt;/<span class="hljs-name">Tiles</span>&gt;</span></span>
    )
  }
}

TilesStyles.js:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Tiles = styled.div<span class="hljs-string">`
  padding: 20px 10px;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Tile = styled.div<span class="hljs-string">`
  flex: 1 1 auto;
  ...
  display: flex;

  &amp; &gt; div {
    flex: 1 0 auto;
  }
`</span>

Notice that this component is purely presentational. It defines its style and wraps whatever children it receives inside another styled DOM element that defines what tiles look like. It’s a good example of what your generic presentational components will look like architecturally.

Then, we need to define what a recipe looks like. We need a container component to describe the relatively complex DOM as well as define the style when necessary. We end up with this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecipeContainer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
  onChangeServings (e) {
    <span class="hljs-keyword">let</span> {changeServings} = <span class="hljs-keyword">this</span>.props
    changeServings(e.target.value)
  }

  render () {
    <span class="hljs-keyword">let</span> {title, ingredients, instructions, time, servings} = <span class="hljs-keyword">this</span>.props

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Recipe</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Title</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">Title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{time}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Serving
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">min</span>=<span class="hljs-string">"1"</span> <span class="hljs-attr">max</span>=<span class="hljs-string">"1000"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{servings}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.onChangeServings.bind(this)}/</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Ingredients</span>&gt;</span>
          {ingredients.map((ingredient, i) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">Ingredient</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span> <span class="hljs-attr">servings</span>=<span class="hljs-string">{servings}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"name"</span>&gt;</span>{ingredient.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"quantity"</span>&gt;</span>{ingredient.quantity * servings} {ingredient.unit}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Ingredient</span>&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Ingredients</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          {instructions.map((instruction, i) =&gt; (<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>&gt;</span>{instruction}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Recipe</span>&gt;</span>
    )
  }
}
</span>

Notice here that the container does some DOM generation, but it’s the only logic it contains. Remember that you can define nested styles, so you don’t need to make a styled element for each tag that requires styling. It’s what we do here for the name and quantity of the ingredient item. Of course, we could split it further and create a new component for an ingredient. That is up to you—depending on the project complexity—to determine the granularity. In this case, it is just a styled component defined along with the rest in the RecipeStyles file:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Recipe = styled.div<span class="hljs-string">`
  background-color: <span class="hljs-subst">${theme('colors.background-highlight')}</span>;
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Title = styled.div<span class="hljs-string">`
  font-weight: bold;
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Ingredients = styled.ul<span class="hljs-string">`
  margin: 5px 0;
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Ingredient = styled.li<span class="hljs-string">`
  &amp; .name {
    ...
  }

  &amp; .quantity {
    ...
  }
`</span>

For the purpose of this exercise, I have used the ThemeProvider. It injects the theme in the props of styled components. You can simply use it as 

1
color: ${props =&gt; props.theme.core_color}

, I am just using a small wrapper to protect from missing attributes in the theme:


1
<span class="hljs-keyword">const</span> theme = <span class="hljs-function">(<span class="hljs-params">key</span>) =&gt;</span> (prop) =&gt; _.get(prop.theme, key) || <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">'missing key'</span>, key)

You can also define your own constants in a module and use those instead. For example: 

1
color: ${styleConstants.core_color}

Pros

A perk of using styled-components is that you can use it as little as you want. You can use your favorite UI framework and add styled-components on top of it. This also means that you can easily migrate an existing project component by component. You can choose to style most of the layout with standard CSS and only use styled-components for reusable components.

Cons

Designers/style integrators will need to learn very basic JavaScript to handle variables and use them in place of Sass/Less.

They will also have to learn to navigate the project structure, although I would argue that finding the styles for a component in that component’s folder is easier than having to find the right CSS/Sass/Less file that contains the rule you need to modify.

They will also need to change their tools a bit if they want syntax highlighting, linting, etc. A good place to start is with this Atom plugin and this babel plugin.

Port php mysql scripts to php 7.0 from 5.x version

Recently I got a script or series of scripts that were written for PHP 5.6x and hence used mysql_connect which as you know by now does not work with PHP 7.0. Since there were number of scripts, I thought it would be waste of time to change them manually and wrote a script to fix them. If you have similar situation then probably this few lines could help you.

Since my scripts did not use all the functions so I did not put the sed commands for all of them but you get the idea 🙂

#!/bin/bash - 
#===============================================================================
#
#          FILE: fix_mysql.sh
# 
#         USAGE: ./fix_mysql.sh 
# 
#   DESCRIPTION: 
# 
#       OPTIONS: ---
#  REQUIREMENTS: ---
#          BUGS: ---
#         NOTES: ---
#        AUTHOR: Amit Agarwal (aka), 
#  ORGANIZATION: 
#       CREATED: 03/23/2018 16:35
# Last modified: Fri Mar 23, 2018  04:36PM
#      REVISION:  ---
#===============================================================================

set -o nounset                              # Treat unset variables as an error


### Run as 
#### find . -type f -name \*php -exec ~/fixmysql.sh {} \;

####

# mysql_affected_rows -> mysqli_affected_rows($link)
# mysql_close -> mysqli_close($link)
# mysql_data_seek -> mysqli_data_seek( $result, $offset)
# mysql_errno -> mysqli_errno( $link)
# mysql_error -> mysqli_error( $link)
# mysql_fetch_array -> mysqli_fetch_array( $result, $type)
# mysql_fetch_assoc -> mysqli_fetch_assoc( $result)
# mysql_fetch_lengths -> mysqli_fetch_lengths( $result )
# mysql_fetch_object -> mysqli_fetch_object( $result, $class, $params)
# mysql_fetch_row -> mysqli_fetch_row( $result)
# mysql_field_seek -> mysqli_field_seek( $result, $number)
# mysql_free_result -> mysqli_free_result(result)
# mysql_get_client_info -> mysqli_get_client_info( $link)
# mysql_get_host_info -> mysqli_get_host_info( $link)
# mysql_get_proto_info -> mysqli_get_proto_info( $link)
# mysql_get_server_info -> mysqli_get_server_info( $link)
# mysql_info -> mysqli_info( $link)
# mysql_insert_id -> mysqli_insert_id( $link)
# mysql_num_rows ->  mysqli_num_rows( $result)
# mysql_ping -> mysqli_ping( $link)
# mysql_query -> mysqli_query( $link, $query)
# mysql_real_escape_string -> mysqli_real_escape_string( $link)
# mysql_select_db - > mysqli_select_db( $link, $database)
# mysql_set_charset -> mysqli_set_charset( $link, $charset)
# mysql_stat -> mysqli_stat( $link)
# mysql_thread_id -> mysqli_thread_id( $link)
######


file=$1
sed -i 's/mysql_connect/mysqli_connect/g' $file
sed -i 's/mysql_query(/mysqli_query($con,/g' $file
sed -i 's/mysql_error/mysqli_error/g' $file
sed -i 's/mysql_select_db(/mysqli_select_db($con,/g' $file
sed -i 's/mysql_affected_rows/mysqli_affected_rows($con,/' $file
sed -i 's/mysql_escape_string(/mysqli_escape_string($con/' $file 
sed -i 's/mysql_real_escape_string(/mysqli_real_escape_string($con/' $file 
sed -i 's/mysql_fetch_array/mysqli_fetch_array/g' $file
sed -i 's/mysql_fetch_assoc/mysqli_fetch_assoc/g' $file
sed -i 's/mysql_fetch_row/mysqli_fetch_row/g' $file
sed -i 's/mysql_select_db/mysqli_select_db/g' $file

Eight CSS Tips for Advanced Layouts and Effects

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

1
:first-child

and

1
:last-child

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

1
.active

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

1
box-sizing

for all elements to

1
border-box

. 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

1
width: 200px

div, with

1
20px

padding and a

1
2px

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.

1
box-sizing: border-box

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.

1
height: 100%

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

1
.container

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

Now

1
.container

will remain a square no matter how wide it becomes.

1
overflow: hidden

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

1
.container

’s top and left through

1
position: absolute

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

1
.container

, and change

1
.container

’s

1
padding-bottom

to match the video’s aspect ratio.

1
position: relative

for

1
.container

ensures that the

1
iframe

absolute positioning works properly. The new

1
padding-bottom

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

1
font-size

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

1
em

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

1
font-size

.

An element with a

1
font-size

of 40px, a width of

1
2em

, and a height of

1
1em

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

Want to change

1
.container

’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

1
display: table

, then convert the inner element into a CSS

1
table-cell

. Or just use CSS Flexbox.

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

1
line-height

:

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

1
.container

’s display to

1
table

, then use

1
display: table-cell

and

1
vertical-align: middle

for

1
.text

:

Think of this CSS trick as the vertical equivalent of

1
margin: 0 auto

. 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

1
margin-bottom

value, and cancel that out with an equally large

1
padding-bottom

. CSS tables and Flexbox also work.

Using

1
float

or

1
display: inline-block

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

Note the use of

1
box-sizing: border-box

to properly size the

1
.cols

. 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

1
overflow: hidden

to

1
.row

. Then set each

1
.col

’s

1
margin-bottom

to 99999px and its

1
padding-bottom

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

1
.col

’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

1
vertical-align: middle

).

7. Going Beyond the Box

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

The solution: Use

1
transform: rotate(x)

, or

1
border-radius

.

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.

  • 1
    .pane-background

    , its child

    1
    .mask-box

    , and its grandchild

    1
    .image

    are all set to

    1
    position: absolute

    . Each element has different

    1
    top

    ,

    1
    left

    ,

    1
    bottom

    , and

    1
    right

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

  • 1
    .mask-box

    is rotated 2 degrees (counter-clockwise).

  • 1
    .image

    is rotated -2 degrees to counteract

    1
    .mask-box

    ’s rotation.

  • 1
    .mask-box

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

    1
    .image

    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

1
border-radius: 100%

to the

1
img

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

1
invert

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

1
!important

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?

1
hue-rotate(180deg)

just creates the same effect as

1
invert(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.