Getting Fancy: Animating text

Depending on the context and the type of text you’re using animations can be useful. CSS Animation Level 1 provides a way to animate CSS properties over time. It uses key frames to create the animations.

We will work through an example similar to the Mozilla Developer Network basic animation example. The same or similar process can be used for other types of animations.

The first thing we do is work setting up the animations in the elements we want, in this case, h1. Also note that we have to set up each attribute twice and maybe 3 times: One with the Mozilla/Firefox prefix (-moz), one for Chrome, Opera and Safari (-webkit) and one without a prefix to prepare for when vendor prefixes are no longer needed.

The attributes we set up are:

  • Duration: How long will the animation last
  • Name: The name of the animation we will use. We’ll define the animation below
h1 {
  -moz-animation-duration: 3s;
  -webkit-animation-duration: 3s;
  animation-duration: 3s;
  -moz-animation-name: slidein;
  -webkit-animation-name: slidein;
  animation-name: slidein;
}
    

Once we set up the animation parameters we need to define the animation. We also have to do this three times, One for Firefox, one for Webkit-based browsers and one without a prefix to future proof our code. Each keyframes selector defines a beginning and ending state for the chosen object. In this case we move h1 heading from left to right and decrease its width at the same time. All these tasks will be done in 3 seconds (as specified by the *-animation-duration attribute of the h1 tag.)

@-moz-keyframes slidein {
  0% { margin-left:100%; width:300%; }
  100% { margin-left:0%; width:100%; }
}

@-webkit-keyframes slidein {
  0% { margin-left:100%; width:300%; }
  100% { margin-left:0%; width:100%; }
}

@keyframes slidein {
  0% { margin-left:100%; width:300%; }
  100% { margin-left:0%; width:100%; }
}

There is another syntax available online that uses keywords (from, to). They are equivalent but I recommend using percentages since they make more sense when inserting additional steps for an animation.

This is just the beginning. We can add additional frames to the key frames selector to make the animation smoother or to add additional steps and animation types to the process. We’re also able to animate color transitions, like transforming the background color of an element through a series of steps.

There is also a Web Animations API editor’s draft that allows developers to use JavaScript to create and control animations. I mention it here but wil not cover it as it’s a Javascript API I’m still in the process of learning.

Just like with transformation: Just because you can it doesn’t mean you should. As great as animations are they take time and may detract from your audience’s attention. Animations can also cause performance issues that you need to consider.

Links and resources

Getting fancy: CSS Transformations

One of the most intriguing things we can do with text is change its position and the way it looks on the screen with nothing but CSS in browsers that support it. The good news is that all browsers except IE8 and Opera Mini support transformations so we won’t have to do workarounds.

Example of what you can do with transitions and shapes
An example of what is possible with CSS shapes and transformations (taken from A List Apart’s article CSS Shapes 101 by Sara Soueidan.)

We’ll start with rotating the header of our content 90 degrees and move it down the column.

[codepen_embed height=”373″ theme_id=”2039″ slug_hash=”ZGJJvy” default_tab=”result” user=”caraya”]See the Pen CSS Content Rotation – Take 1 by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

It looks good but I think it can look better. When we move it sideways the text looks very small and when we make the font larger it forces the text into 2 rows… and that’s not what I want… I want the larger text to stay in one column.

What I realized was that I had to change the design. Rather than keep the heading inside the content area, it would work better if we move the h2 element outside the content area and style it separately.

Transformations are very dependent on the dimensions of the content you’re working with. The codepen below shows the heading in the smallest media query I set up for the demo (800px wide). The heading is not rotated but displayed in above the text as in a regular page.

[codepen_embed height=”830″ theme_id=”2039″ slug_hash=”MwvWYd” default_tab=”result” user=”caraya”]See the Pen CSS Content Rotation Using Media Queries by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

But if you look at a screenshot below, you’ll see what the code work when you set the screen as wide as possible.

http:https://i0.wp.com/publishing-project.rivendellweb.net/wp-content/uploads/2015/06/full-width-translated-object.png?resize=525%2C292&ssl=1
http://publishing-project.rivendellweb.net/wp-content/uploads/2015/06/full-width-translated-object.png

Media queries would be the best solution to accommodate for all screen sizes. You will have to decide if Media Queries and Vendor prefixes is worth the effort and how many media queries you would have to create for your code to look good in your target device(s). It’s not a perfect solution, it requires tons of work and needs to be adjusted for all your target breakpoints and devices.

This is just the beginning of what you can do. Mozila Developers Network (MDN) provides a very good overview of CSS transformations to show what you can do.

Because this is dependent on screen resolution (when is a pixel is not a pixel) you must test in your target devices. Also : Just because you can it doesn’t mean you should. As great as transformations are they take time and may detract from your audience’s attention.

Links and Resources

Using SASS maps in media queries

Version 3 of SASS introduced the map data type. If you’ve done work in any other programming type you’ll problbly be familiar with maps as associate arrays or hashes; SASS uses the same principle: maps are a collection of key-value pairs.

How does this affect typography? Simple: We can build a map to store media query breakpoints and associated font sizes and use those in our code without having to remember what rules we set up and how we

SASS Maps

Sass script maps are a list of one or more key-value pairs assigned to a variable. We can use the map with looping functions to get one result for each key-value pair on the map when running the loop. Let’s use a basic set of colors for our social media profiles as an example:

$sm-profiles: (
  facebook: #3b5998,
  flickr: #0063db,
  github: #4183c4,
  googleplus: #dd4b39,
  linkedin: #007bb6,
  twitter: #00aced,
  vimeo: #aad450,
  youtube: #b00
);

We then create a function that loops through our map and, for each profile value, we make the background equal to the value of the profile key. The code to do that is show below:

@each $profile, $bgcolor in $sm-profiles {
  .profile-link--#{$profile}:focus,
  .profile-link--#{$profile}:hover {
    background: $bgcolor;
  }
}

And the result for Vimeo (using the $sm-profiles map and the function discussed above) looks like this:

.profile-link--vimeo:focus,
.profile-link--vimeo:hover {
  background: #aad450;
}

Applying maps to typography

$breakpoints: (
  small : 480px,
  medium: 700px,
  large : 1024px
);

$p-font-sizes: (
  null  : (15px, 1.3),
  small : 16px,
  medium: (17px, 1.4),
  900px : 18px,
  large : (19px, 1.45),
  1440px: 20px,
);

Although line-height values can be defined using any valid CSS unit (percentages, pixels, ems, etc.), “unitless” values are recommended and preferred.

We then modify the mixin to include line height when generating the CSS. We do it using the nth SASS function as it allow us to get a given element in a list, in this case the second element that correspond to line-height.

In order to make sure that there is a value for our line-height attribute, we test if the element in the map has more than one value (its length is greater than 1) and only add line-height if this is true.

@mixin font-size($fs-map, $fs-breakpoints: $breakpoints) {
  @each $fs-breakpoint, $fs-font-size in $fs-map {
    @if $fs-breakpoint == null {
      @include make-font-size($fs-font-size);
    }
    @else {
      // If $fs-font-size is a key that exists in
      // $fs-breakpoints, use the value
      @if map-has-key($fs-breakpoints, $fs-breakpoint) {
        $fs-breakpoint: map-get($fs-breakpoints, $fs-breakpoint);
      }
      @media screen and (min-width: $fs-breakpoint) {
        @include make-font-size($fs-font-size);
      }
    }
  }
}

// Utility function for mixin font-size
@mixin make-font-size($fs-font-size) {
  @if type-of($fs-font-size) == "list" {
    font-size: nth($fs-font-size, 1);
    // If $fs-font-size is a list, include
    // both font-size and line-height
    @if (length($fs-font-size) > 1) {
      line-height: nth($fs-font-size, 2);
    }
  }
  @else {
    font-size: $fs-font-size;
  }
}

The mixin checks to see whether the value of the key in the font-sizes map is a list as opposed to a font-size value. If it’s a list, then it gets the correct value from the list by index value, with the help of the nth function. It assumes that the first value is the font size and the second is the line height. Let’s see it in action:

p {
  @include font-size($p-font-sizes);
}

The result looks like this:

/* line 52, /Users/carlos/code/docs/maps-typography.scss */
p {
  font-size: 15px;
  line-height: 1.3; }

  @media screen and (min-width: 480px) {
    p {
      font-size: 16px; }
    }

  @media screen and (min-width: 700px) {
    p {
      font-size: 17px;
      line-height: 1.4; }
    }

  @media screen and (min-width: 900px) {
    /* line 52, /Users/carlos/code/docs/maps-typography.scss */
    p {
      font-size: 18px; }
    }

  @media screen and (min-width: 1024px) {
    /* line 52, /Users/carlos/code/docs/maps-typography.scss */
    p {
      font-size: 19px;
      line-height: 1.45; }
    }

  @media screen and (min-width: 1440px) {
    /* line 52, /Users/carlos/code/docs/maps-typography.scss */
    p {
      font-size: 20px; }
    }

/*# sourceMappingURL=maps-typography.css.map */

Moving forward

In and of itself these maps are pretty good. To enhance them we can do one of the following

  • Add other attributes to the p-font-size map to represent attributes like word or character spacing, font stretching and other attributes that we want to change for media queries
  • Add other maps equivalent to p-font-size for other elements that need to change based on media queries
  • Build more complex maps that would include values for all the elements we want to change in a media query (such as paragraph, headings, line height and others) and then modify the mixin to handle the new values and, maybe, define the mixin at the top of the style sheet

Links and resources

Multicolumn layouts

CSS 3 allows you to create multi column layouts without cheating. According to caniuse.com the feature is supported to some degree by all browser vendors. We’ll explore some of the things you can do with columns and where the limitations are.

Please note that these examples use -moz and -webkit prefixes (for Chrome). To make sure the column examples work when you make changes you have to change all three values (prefixed and unprefixed.) This PITA makes columns another great candidate for autoprefixer or a SASS mixin.

Finally, because this is still a work in progress, some aspects of the spec is not implemented in all browsers. If this is an issue for you please consider using polyfills.

Creating multi column text: counting columns

The easiest way to work with columns is to tell CSS how many columns you want using the (prefixed) column-count property. This will tell the bowser how many columns to use. It will stick to that number of columns no matter what. They will be as wide or narrow as they need to be but the browser will always honor the number of clumns you tell it to use.

[codepen_embed height=”665″ theme_id=”2039″ slug_hash=”oXexXr” default_tab=”result” user=”caraya”]See the Pen Counting Columns by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Creating multi column text: counting width

The opposite effect is to use the (also prefixed) column-width property. Where column count takes a single integer without unit as its value, column-width takes a value with unit (like the 150px used in CSS Example 12-2) and will create as many columns of that width as there is space available. Contrast CSS Example 12-1 and 12-2. Where 12-1 sticks to the two columns, 12-2 creates as many 150px columns as it can with the space available. Try narrowing the window and see what happens in example 12-2… the number of columns will shrink a the space available decreases.

[codepen_embed height=”671″ theme_id=”2039″ slug_hash=”NqvNGj” default_tab=”result” user=”caraya”]See the Pen Measuring Columns Width by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Creating multi column text: the shorthand method

Some times I’m lazy and I want to just make columns work. Fortunately there is a shorthand syntax for column-width and column-count. It’s just columns. Examples of legal values taken from the CSS3 colmn module specification:

body {
  columns: 12em;      /* column-width: 12em; column-count: auto */
  columns: auto 12em; /* column-width: 12em; column-count: auto */
  columns: 2;         /* column-width: auto; column-count: 2 */
  columns: 2 auto;    /* column-width: auto; column-count: 2 */
}

As we can see it’s either a column-count or column-width, not both.

Column Gap

In both examples, the browser took it upon itself to create a gap between columns. In this case it was OK but it is not always the case. Fortunately the multi column spec gives you the ability of specifying a gap between the columns of your text.

[codepen_embed height=”675″ theme_id=”2039″ slug_hash=”RPZarP” default_tab=”result” user=”caraya”]See the Pen CSS Column Gap by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

As you can see in the examples, the further apart we put the columns the easier each column it is to read but we get a smaller space to work with the overall text content.

[codepen_embed height=”640″ theme_id=”2039″ slug_hash=”gpxrMM” default_tab=”result” user=”caraya”]See the Pen CSS Column Gap – 4em by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Column Rules

In this context, rules are vertical lines between the columns to help differentiate the columns and prevent runon text. We can combine this with gutter/gap as in example 12-4 to create a more pleasing reading experience.

[codepen_embed height=”527″ theme_id=”2039″ slug_hash=”pJryEa” default_tab=”result” user=”caraya”]See the Pen Columns with rules between columns by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Spanning Columns

There are times when it’s nice to have an element (a div that holds byline information, for example) span the full width of our content area without regard to the number of columns. CSS Columns module provides the column-span rule to do just that.

This is where we see the first deviation from the specification. According to MDN, Firefox does not support column-span at all, it displays the content in its own column regardless of the settings authors choose.At least the result is not too bad…

[codepen_embed height=”527″ theme_id=”2039″ slug_hash=”mJMPOP” default_tab=”result” user=”caraya”]See the Pen Spanning Columns with CSS by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Filling Columns

So far columns are filled unevenly in all our examples. The right most column is shorter (sometimes considerably so.) The column-fill property will, when supported, make all the columns even in length. Currently only firefox will support the column-fill property.

[codepen_embed height=”675″ theme_id=”2039″ slug_hash=”XbadMo” default_tab=”result” user=”caraya”]See the Pen Column Fill by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Column Breaks

One of the most complex aspects of working with multi column content is how to prevent breaks inside, before or after a given piece of text. It gets even more complex when we factor columns into the mix. We’ll explore how to make sure that breaks work and that they actually do what we want them to:

In this case we’ll make the title h2 element stand alone in its own column and move the body text to the right and keep in the two column format. In the older days you’d accomplish this with table-based layouts but now it can be done using only CSS in bowsers that support it.

[codepen_embed height=”675″ theme_id=”2039″ slug_hash=”pJryPV” default_tab=”result” user=”caraya”]See the Pen CSS Column Break – Take 1 by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

This is easy but it gets more complicated when we look at other values for break-before, break-after and break-inside that describe whether we should break before the element, after the element or inside the element. We’ll try another example where we’ll tell the browser to explicitly break after a paragraph… the results may not be what you’d expect.

I assumed, incorrectly as it turns out, that the break would still keep the content inside the parent’s container but as you can see it did not. In order to get the effect I wanted I had to provide smaller gap between columns and give different break styles to even and odd paragraphs. The second try looks better but it is brittle… although my tests have worked consistently I keep thinking there may be a combination of browser width where this will break.

[codepen_embed height=”521″ theme_id=”2039″ slug_hash=”aOyNwx” default_tab=”result” user=”caraya”]See the Pen CSS Column Break – Take 3 by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Mixins and Autoprefixer

If you’re a SASS monkey then you can use a mixin like the one below to work with columns. The mixing makes it easier for you to work with prefixes by abstracting the prefixes and, where it makes sense, providing sensible defaults.

@mixin column-attribs ($cols, $gap, $fill: balance, $span: none){
  /* How many columns? */
  -moz-column-count: $cols;
  -webkit-column-count: $cols;
  column-count: $cols;
  /* Space between columns */
  -moz-column-gap: $gap;
  -webkit-column-gap: $gap;
  column-gap: $gap;
  /* How do we fill the content of our columns, default is to balance */
  -moz-column-fill: $fill;
  -webkit-column-fill: $fill;
  column-fill: $fill;
  /* Column span, defaul is not to span columns */
  -moz-column-span: $span;
  -webkit-column-span: $span;
  column-span: $span;
}
.col2 {
  width: 100%;
  @include column-attribs (2, 20px);
}

And the result looks like this:

.col2 {
  width: 100%;
  /* How many columns? */
  -moz-column-count: 2;
  -webkit-column-count: 2;
  column-count: 2;
  /* Space between columns */
  -moz-column-gap: 20px;
  -webkit-column-gap: 20px;
  column-gap: 20px;
  /* How do we fill the content of our columns, default is to balance */
  -moz-column-fill: balance;
  -webkit-column-fill: balance;
  column-fill: balance;
  /* Column span, defaul is not to span columns */
  -moz-column-span: none;
  -webkit-column-span: none;
  column-span: none;
}

I understand that there are designers who are not comfortable with SASS/SCSS. For those people I think the best solution is to use automatic prefixer tools, either directly or as part of an automated workflow. I’ve chosen to use autoprefixer in a Grunt workflow.

I won’t go into details about the Grunt workflow but if you’re familiar with Grunt it shouldn’t be too hard to add Autoprefixer to the process. If you want to look at a (somewhat disorganized) reference you can look at the Gruntfile I created for this project.

Links and Resources

From MDN

Orphans and Widows

The orphans CSS property refers to the minimum number of lines of text in a container that must be left at the bottom of the page. This property is normally used to control how page breaks occur.

In typography, a widow is the last line of a paragraph appearing alone at the top of a page. The widows CSS property defines how many lines must be left on top of a new page.

In browsers that support the properties, widows and orphans allow us to control how content is displayed on multi column layouts and/or printed media. It is a complement to break-* in that widows and orphans provide an alternative way to break content, just set the values high enough and the content will break (although it may become harder to read.)

[codepen_embed height=”593″ theme_id=”2039″ slug_hash=”RPeyNy” default_tab=”result” user=”caraya”]See the Pen CSS Columns Fill by Carlos Araya (@caraya) on CodePen.[/codepen_embed]

Compare the exaple above (CSS Columns Fill) with the one below (Widows and Orphans.)

In the balanced columns example, how can you tell whether 1 or 2 lines at the bottom of the div are part of the paragraph in the next column versus a standalone paragraph?

CSS orphans and widows resolve the issue by moving all the text to the next column (the 2 lines are smaller than the value we set for orphans in the CSS)

[codepen_embed height=”653″ theme_id=”2039″ slug_hash=”xGLLPW” default_tab=”result” user=”caraya”]See the Pen Widows and Orphans by Carlos Araya (@caraya) on CodePen.[/codepen_embed]