Friday, April 17, 2015

Grid Item Animation Layout

Grid Item Animation Layout

A responsive, magazine-like website layout with a grid item animation effect that happens when opening the content.

Today we'd like to share a simple animated grid layout with you. The responsive layout has a sidebar and grid items that animate to a larger content area when clicked. In the first demo the content area fills the grid (inspired by a concept by Virgil Pana) and in the second demo, the whole layout moves to the left while the grid item is expanding (inspired by this Dribbble shot by Sam Thibault).

The expanding element (which is a dummy element and not the grid item itself) is not animating in width and height but instead its original dimensions are already of the expanded size and we simply scale it down initially. By setting classes, we control the transitions of all the elements: the grid item elements' disappearance and the content elements' appearance (and vice versa when we close an opened content panel).

Grid Item Animation Layout

The layout is responsive down to mobile using a media query technique that involves setting the breakpoints based on the grid item size and the sidebar. For this we use Sass, which allows us to set these kind of variables easily. The approach we are using here is mainly mobile-first, but we also do some specific restructuring for small screens.

* Please note that this layout uses some modern techniques that involve viewport units, transitions, flexbox and other properties that will only work in modern browsers.

The second demo is a bit more experimental and it might not behave as expected in all browsers. Internet Explorer seems to have some issues with transitions on transforms that use calc().

This layout is focused on the expansion effect of the grid item and many elements are simple dummies (the loader, the filter in the top bar and the "load more" in the footer of the grid).

The main markup looks as follows:


The Sass files of this project are divided into a main style file and two partials, one for the base styles and one for the media queries. Each of the demos will have a unique style Sass file (style1.scss and style2.scss) where we initiate some variable and redefine some styles if necessary (as in demo 2). There are many ways of organizing your project in Sass; this was one convenient way to do it for these two demos. If you'd like to use one of them, make sure to refactor your style declarations. If you are not familiar with Sass, you can simply use and adjust the generated CSS files.

An example for the main demo Sass file is as follows:

$item_width: 300px;
$sidebar_width: 300px;
$color_primary: #fafafa;
$color_secondary: #fff;
$color_link: #81c483;
$anim-time: 0.5s;

@import "base";
@import "mediaqueries";

The variables needed in the base and the media queries Sass files are defined here.

Grid Item Animation Layout

The media query breakpoints are defined by the amount of items we want to be visible in the grid and the sidebar (no prefixes shown):

/* Viewport sizes based on column number and sidebar */
$viewport_xs:  $item_width + $sidebar_width; /* 1 column */
$viewport_s:  $item_width * 2 + $sidebar_width; /* 2 columns */
$viewport_m:  $item_width * 3 + $sidebar_width; /* 3 columns */
$viewport_l:  $item_width * 4 + $sidebar_width; /* 4 columns */
$viewport_xl:  $item_width * 5 + $sidebar_width; /* 5 columns */
$viewport_xxl:  $item_width * 6 + $sidebar_width; /* 6 columns */

@media screen and (min-width: $viewport_xs) {
 html, 
 body, 
 .container, 
 .main {
  height: 100vh;
 }

 .main {
  height: 100%;
  margin-left: $sidebar_width;
 }

 .content__item {
  font-size: 1em;
 }

 .grid__item {
  padding: 45px 45px 30px;
 }
}

@media screen and (min-width: $viewport_s) {
 .grid {
  display: flex;
  flex-wrap: wrap;
 }

 /* 2 columns */
 .grid__item {
  width: 50%;
  border: none;
 }

 .grid__item::before {
  top: 5px;
  right: 5px;
  bottom: 5px;
  left: 5px;
  border: 1px solid rgba(74,74,74,0.075);
  transition: opacity 0.3s;
 }

 .grid__item:hover::before,
 .grid__item:focus::before {
  border: 3px solid rgba(129,196,131,0.5);
 }

 .grid__item--loading.grid__item::before {
  opacity: 0;
 }
}

@media screen and (min-width: $viewport_m) {
 /* 3 columns */
 .grid__item {
  width: 33.333%;
 }
}

@media screen and (min-width: $viewport_l) {
 /* 4 columns */
 .grid__item {
  width: 25%;
 }
}

@media screen and (min-width: $viewport_xl) {
 /* 5 columns */
 .grid__item {
  width: 20%;
 }
}

@media screen and (min-width: $viewport_xxl) {
 /* 6 columns */
 .grid__item {
  width: 16.66%;
 }
}

/* small screen changes for sidebar (it becomes an off-canvas menu) */
@media screen and (max-width: $viewport_xs - 1px) {
 .sidebar {
  transform: translate3d(-100%,0,0);
 }
 .sidebar.sidebar--open {
  transform: translate3d(0,0,0);
 }
 .sidebar.sidebar--open ~ .main {
  pointer-events: none;
 }
 .top-bar {
  padding: 22px 15px 10px 60px;
 }
 .menu-toggle {
  display: inline-block;
 }
 .sidebar .close-button {
  opacity: 1;
  top: 15px;
  right: 15px;
  pointer-events: auto;
 }
 .title--full {
  font-size: 2em;
 }
 .content__item {
  padding: 80px 20px 40px;
 }
 .close-button {
  padding: 10px 20px;
 }
 .close-button::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  background: $color_secondary;
  border-bottom: 1px solid $color_primary;
  width: 100vw;
  height: 50px;
  pointer-events: none;
  z-index: -1;
 }
}

This technique can come in handy when dealing with grid layouts. Optimally, we'd not have that last media query at all if we want to strictly follow a mobile-first approach. But since these styles are exclusively valid only for small screens, we don't want to be redefining and overwriting styles for larger screens.

Have a look at the layout and the effect and dig into the source, we really hope you find this template useful and inspiring!

View Demo or Download the files

Tuesday, April 14, 2015

Keeping it simple: coding a carousel

coding a carousel

One of the things that drives me crazy in our "modern development" world is our fetish of over-complicating things. We build solutions, and then we add layers and layers of complexity for the sake of "making them easier to maintain". In many cases, this is a fool's errand as the layers of complexity and with them the necessary documentation make people not use our solutions. Instead, in many cases, people build their own, simpler, versions of the same thing and call it superior. Until this solution gets disputed and the whole dance happens once again.

In this article I want to approach the creation of a carousel differently: by keeping it as simple as possible whilst not breaking backwards compatibility or have any dependencies. Things break on the web. JavaScript might not be loaded, CSS capabilities vary from browser to browser. It is not up to us to tell the visitor what browser to use. And as good developers we shouldn't create interfaces that look interactive but do nothing when you click them.

So, let's have a go at building a very simple carousel that works across browsers without going overboard. You can see the result and get the code on GitHub.

The HTML structure of a carousel

Let's start very simple: a carousel in essence is an ordered list in HTML. Thus, the basic HTML is something like this:

  1. 1
  2. 2
  3. 3
  4. 4

Using this, and a bit of CSS we have something that works and looks good. This is the base we are starting from.

The basic CSS

The CSS used here is simple, but hints at some of the functionality we rely on later:

.carouselbox {
  font-family: helvetica,sans-serif;
  font-size: 14px;
  width: 100px;
  position: relative;
  margin: 1em;
  border: 1px solid #ccc;
  box-shadow: 2px 2px 10px #ccc;
  overflow: hidden;
}

.content {
  margin: 0;
  padding: 0;
}

.content li {
  font-size: 100px;
  margin: 0;
  padding: 0;
  width: 100%;
  list-style: none;
  text-align: center;
}

The main thing here is to position the carousel box relatively, allowing us to position the list items absolutely inside it. This is how we'll achieve the effect. The hidden overflow ensures that later on only the current item of the carousel will be shown. As there is no height set on the carousel and the items aren't positioned yet, we now see all the items.

coding a carousel

The carousel visuals in CSS

A lot of carousel scripts you can find will loop through all the items, or expect classes on each of them. They then hide all and show the current one on every interaction. This seems overkill, if you think about it. All we need is two classes:

  • We need a class on the container element that triggers the functional display of our carousel. This one gets applied with JavaScript as this means the look and feel only changes when the browser is capable of showing the effect.
  • We need a class on the currently visible carousel element. This is the odd one out. All the others don't need any classes.

We can hard-code these for now:

  1. 1
  2. 2
  3. 3
  4. 4

All we need to show and hide the different carousel items is to change the height of the carousel container and position all but the current one outside this height:

.active {
  height: 130px;
}

.active li {
  position: absolute;
  top: 200px;
}

.active li.current {
  top: 30px;
}

You can see this in action here. Use your browser developer tools to move the current class from item to item to show a different one.

coding a carousel

Interaction with Javascript

To make the carousel work, we need controls. And we also need some JavaScript. Whenever you need a control that triggers functionality that only works when JavaScript is executed, a button is the thing to use. These magical things were meant for exactly this use case and they are keyboard, mouse, touch and pen accessible. Everybody wins.

In this case, I added the following controls in our HTML:

  1. 1
  2. 2
  3. 3
  4. 4

Now, here is where the hard-liners of semantic markup could chime in and chide me for writing HTML that is dependent on JavaScript instead of creating the HTML using JavaScript. And they'd be correct to do so. There is nothing that stops me from wrapping this chunk of HTML in a DOM call or innerHTML write-out. However, as buttons are meant to trigger JS functionality, I think it is easier to just keep that in the HTML and allow us thus to style them with much less hassle. As a security precaution, we hide them in the non-active state and show them when the "active" class has been applied:

.active .buttons {
  padding: 5px 0;
  background: #eee;
  text-align: center;
  z-index: 10;
  position: relative;
}

.carouselbox button {
  border: none;
  display: none;
}

.active button {
  display: block;
}

.offscreen {
  position: absolute;
  left: -2000px;
}

The offscreen parts are there to explain what these buttons really mean as the triangle is not enough for some people.

All that is left to make the carousel work is the JavaScript. And here it is:

carousel = (function(){
  var box = document.querySelector('.carouselbox');
  var next = box.querySelector('.next');
  var prev = box.querySelector('.prev');
  var items = box.querySelectorAll('.content li');
  var counter = 0;
  var amount = items.length;
  var current = items[0];
  box.classList.add('active');
  function navigate(direction) {
    current.classList.remove('current');
    counter = counter + direction;
    if (direction === -1 && 
        counter < 0) { 
      counter = amount - 1; 
    }
    if (direction === 1 && 
        !items[counter]) { 
      counter = 0;
    }
    current = items[counter];
    current.classList.add('current');
  }
  next.addEventListener('click', function(ev) {
    navigate(1);
  });
  prev.addEventListener('click', function(ev) {
    navigate(-1);
  });
  navigate(0);
})();
As you can see, by relying on CSS and its built-in crawling of the DOM, there is no need for any loop whatsover. Here's what's going on in this script:
  • We grab all the HTML elements we need with querySelector.
  • We set the counter to 0 – this is the variable that keeps track of which item of the carousel is currently shown.
  • We read the amount of items in the carousel and store them in a variable – this allows us to loop the carousel.
  • We set the current item as the first one in the carousel. The current variable will contain a reference to the element currently visible. All we do when the carousel state changes is remove the CSS class from it and shift it to the other one.
  • We add the class of active to the container element to change its styling and trigger the CSS functionality explained earlier.
  • The navigate method takes a parameter called direction which defines if we should go backwards (negative values) or forwards in the carousel. It starts by removing the current class from the current carousel item, thus hiding it. We then modify the counter and make sure it doesn't go beyond the amount of items available or below 0. In each case we move to the other extreme, thus making the carousel an endless rotating one. We define the new current item and add the class to show it.
  • We apply event handlers to the buttons to navigate forwards and backwards.
  • We show the first carousel item by calling navigate with 0 as the value.
Pretty simple, isn't it? By allowing CSS to do what it is good at, our JavaScript more or less is only about keeping state and shifting classes around.

Getting fancy

The showing and hiding of the items by positioning them in a container with overflow hidden should work in any browser in use these days – even the ones who should be retired. And as all we do is add and remove CSS classes, we can now tap into the beautiful features browsers have these days. Using transition, opacity and transformation, we can add a pretty effect with a few lines of CSS:

.active li {
  position: absolute;
  top: 130px;
 
  opacity: 0;
  transform: scale(0);
  transition: 1s;
}

.active li.current {
  top: 30px;
 
  opacity: 1;
  transform: scale(1);
  transition: 1s;
}

coding a carousel
The beauty of this is that the performance handling, the timing (in case you click too fast) is handled by the browser for us. No need to count FPS or juggle timeouts. As CSS is a one-off state, this also means that browsers that do not support these features simply don't show them instead of throwing an error.

Bullet-proofing our Javascript

When a browser in use doesn't support some JavaScript feature we use, things get trickier. We get an error and things break. Thus, it makes sense to test for the things we use and move on only when there is support for them. In this code, we rely on classList and querySelector, so let's just check for this:

if (!document.querySelector || !('classList' in document.body)) {
    return false;
}

We could get much more paranoid and ensure that all the DOM elements are available before proceeding but this is overkill. If a maintainer forgets to add the carouselbox class to the main element, the error thrown is pretty obvious.

Bonus round: stacking with CSS

One last trick to mention is that if you were to stack all the elements of the carousel visually and only use opacity to blend them then there is a problem with links. You'd always get the link of the first item, no matter which one is shown.

The trick to work around that is user pointer-events: none in your CSS:

.active li {
  position: absolute;
  top: 130px;
 
  pointer-events: none;
  opacity: 0;
  transform: scale(0);
  transition: 1s;
}

.active li.current {
  top: 30px;
 
  pointer-events: auto;
  opacity: 1;
  transform: scale(1);
  transition: 1s;
}

You can see this workaround in action here.

Where to go now

The natural drive as a developer now is to enhance this to allow users to define a different starting element to show, to define lots of preset effects that can be chosen with the data attribute, to allow for non-looping carousels and to define an API to allow other components on the page to interact with the carousel. And an API to create and remove and shuffle items of the carousel. And, and and... All of these are great exercises, but let's ask ourselves: who do we do that for?

We have such amazing functionality built into the platform of the web now. Maybe it is time to stop writing the perfect generic re-usable widget and just stick with simple things and let people extend them when they need to? Who knows, by not doing the work for them, people might learn to be better coders themselves.

Tuesday, April 14, 2015

Understanding Variable Scope in Sass

Variable Scope in Sass
In this article, we'll take a deeper look at variables and variable scope in Sass. The scope of a variable describes the context within which it's defined and therefore where it's available to use.

To start, I'll cover which scopes Sass supports. Then, I'll explain two useful flags we can use to customize the value of a variable. Finally, I'll briefly present the available functions for checking whether a variable exists or not.

Sass Variable Scope

Sass supports two types of variables: local variables and global variables.

By default, all variables defined outside of any selector are considered global variables. That means they can be accessed from anywhere in our stylesheets. For instance, here's a global variable:

$bg-color: green;

On the other hand, local variables are those which are declared inside a selector. Later, we'll examine how we can customize that behavior. But for now, let's see our first example.

Here we define a mixin and then the btn-bg-color variable within it. This is a local variable, and is therefore visible only to the code inside that mixin:

@mixin button-style {
    $btn-bg-color: lightblue;
    color: $btn-bg-color;
}

Next, we can call the mixin as follows:

button { @include button-style; }

The resulting CSS:

button { color: lightblue; }

Imagine, however, that we also want to use this variable (not the mixin) in another selector:

.wrap { background: $btn-bg-color; }

This would give us the following error:

Undefined variable: "$btn-bg-color".

That was to be expected, right? We tried to access a mixin variable, which is locally scoped. Don't worry though, as mentioned above, we'll fix this issue in an upcoming section.

Nested Selectors

It's worth also mentioning that if we declare a variable inside a selector, any other nested selector can access it. Here's an example:

.wrap {
    $bg-color: red;
    &:after {
        background: lighten($bg-color, 10%);
    }
}

This compiles to:

.wrap:after { background: #ff3333; }

However, look at the example below where we define a function, then use that function along with a nested selector:

@function my-function() {
    $text-color: black;
    @return $text-color;
}
     
.wrap {
    color: my-function();
    &:after{
        background: $text-color;
    }
}

If we try to compile this, we'll get the same error discussed before. Again, that happens because we can't access the text-color variable. It isn't directly defined within the parent selector, but inside the function that our selector calls.

Variable Names

Global and local variables can have the same names. To demonstrate that behavior, we'll work on a fourth example:

$text-color: tomato;
 
@mixin button-style {
    $text-color: lime;
    color: $text-color;
}
     
@mixin link-style {
    $text-color: black;
    color: $text-color;
}

Here we've defined three different variables (text-color) with the same name. The first one is a global variable, while the other two are local.

Here are some styles making use of them:

button { @include button-style; }
a { @include link-style; }
.wrap { background: $text-color; }

And the generated CSS:

button { color: lime; }
a { color: black; }
.wrap { background: tomato; }

Is that what you were expecting?

Keep in mind that we won't see these styles unless we compile with the current version of Sass (3.4). For example, supposing that we use Sass 3.3, our CSS output would look like this:

button { color: lime; }
a { color: black; }
.wrap { background: black; }

Notice the difference in the background color of the .wrap selector. This happens because according to the earlier Sass versions (same for LibSass), if we locally redefine the value of a global variable (e.g. text-color), this will be the variable's new (global) value. So, in our example the compiled styles depend on the order we declare the variable and the mixins.

The default flag

This flag allows us to set the value of a variable in case it hasn't already been set or its current value is null (treated as unassigned). To better explain how we can take advantage of it in a real scenario, let's suppose that we have a project with the following structure:

Project-Name/
├── ...
├── css/
│ └── app.css
└── scss/
├── _config.scss
├── _variables.scss
├── _mixins.scss
└── app.scss

The app.scss file looks like this:

@import "config";
@import "variables";
@import "mixins";
     
button { @include button-style; }
 
// more styles

Let's see the contents of the partial files.

Firstly, the variables.scss file contains our variables:

$btn-bg-color: lightblue !default;
$btn-bg-color-hover: darken($btn-bg-color, 5%);
     
// more variables

Notice the default flag assigned to the btn-bg-color variable.

Secondly, the mixins.scss file includes our mixins:

@mixin button-style ($bg-color: $btn-bg-color, $bg-color-hover: $btn-bg-color-hover) {
    background-color: $bg-color;
    // more styles
    &:hover {
        background-color: $bg-color-hover;
        // more styles  
    }
}
     
// more mixins

Then, the generated app.css file will be as follows:

button { color: lightblue; }
button:hover { background-color: #99cfe0; }

So, our buttons come with default styles. But let's suppose that we want to have the option to overwrite them by applying our custom values. To do this, we can reassign the desired (default) variables in the config.scss partial file:

$btn-bg-color: chocolate;
// more variables

Setting the value of this variable to chocolate will result in ignoring the corresponding value (lightblue) that has received the default flag. Therefore, the generated CSS changes as we can see below:

button { color: chocolate; }
button:hover { background-color: #bc5e1b; }

Note: in case we haven't added the default flag to the btn-bg-color variable, our CSS would be, due to the cascading nature of CSS, as follows:

button { color: lightblue; }
// hover styles

The global flag

This second flag helps us change the scope of a local variable.

Do you remember the error we saw in our first example? Well, that happened because we tried to use the btn-bg-color variable in the .wrap selector. Let's modify our example to include this new flag. Here are the new styles:

@mixin button-style {
    $btn-bg-color: lightblue !global;
    color: $btn-bg-color;
}

button { @include button-style; }

.wrap { background: $btn-bg-color; }

As you can see below, thanks to this flag, the CSS compiles without any errors:

button { color: lightblue; }
.wrap { background: lightblue; }

The global flag is useful, but bear in mind that it's not always good practice to change a variable's scope.

Checking if a Variable Exists

Sass provides two introspection functions for testing whether a variable exists or not. We can use the variable-exists and/or global-variable-exists functions to check if our local and/or global variables exist respectively.

For example, here's a common use case where we define a variable containing the absolute path to a Google Font. Then, we choose to import that font in our stylesheets, but only if the relevant variable has been instantiated.

$google-font: "http://fonts.googleapis.com/css?family=Alegreya";

@if(global-variable-exists(google-font)) {
    @import url($google-font);
}

The result:

@import url("http://fonts.googleapis.com/css?family=Alegreya");

Conclusion

In this article, I introduced you to the concept of variable scope in Sass. To make things clearer we looked at different examples, so hopefully you now have a good understanding of how scope works. You can find all the examples of this article in this SassMeister gist.

Tuesday, April 07, 2015

Simple Inheritance with JavaScript

Simple Inheritance with JavaScript

JavaScript uses a different approach than C# or C++ to create an object-oriented language. It is a prototype-based language. The concept of prototyping implies that behavior can be reused by cloning existing objects that serve as prototypes. Every object in JavaScript decends from a prototype which defines a set of functions and members that the object can use. There is no class. Just objects. Every object can then be used as a prototype for another object.

This concept is extremely flexible and we can use it to simulate some concepts from OOP like inheritance.

Implementing Inheritance

Let's visualize what we want to create with this hierarchy using JavaScript:

Simple Inheritance with JavaScript

First of all, we can create ClassA easily. Because there are no explicit classes, we can define a set of behavior (A class so…) by just creating a function like this:

var ClassA = function() {
    this.name = "class A";
}

This "class" can be instantiated using the new keyword:

var a = new ClassA();
ClassA.prototype.print = function() {
    console.log(this.name);
}

And to use it using our object:

a.print();

Fairly simple, right?

The complete sample is just 8 lines long:

var ClassA = function() {
    this.name = "class A";
}
 
ClassA.prototype.print = function() {
    console.log(this.name);
}
 
var a = new ClassA();
 
a.print();

Now let's add a tool to create "inheritance" between classes. This tool will just have to do one single thing: clone the prototype:

var inheritsFrom = function (child, parent) {
    child.prototype = Object.create(parent.prototype);
};

This is exactly where the magic happens! By cloning the prototype, we transfer all members and functions to the new class.

So if we want to add a second class that will be a child of the first one, we just have to use this code:

var ClassB = function() {
    this.name = "class B";
    this.surname = "I'm the child";
}
 
inheritsFrom(ClassB, ClassA);

Then because ClassB inherited the print function from ClassA, the following code is working:

var b = new ClassB();
b.print();

And produces the following output:

class B

We can even override the print function for ClassB:

ClassB.prototype.print = function() {
    ClassA.prototype.print.call(this);
    console.log(this.surname);
}

In this case, the produced output will look like this:

class B 
I'm the child

The trick here is to the call ClassA.prototype to get the base print function. Then thanks to call function we can call the base function on the current object (this).

Creating ClassC is now obvious:

var ClassC = function () {
    this.name = "class C";
    this.surname = "I'm the grandchild";
}
 
inheritsFrom(ClassC, ClassB);
 
ClassC.prototype.foo = function() {
    // Do some funky stuff here...
}
 
ClassC.prototype.print = function () {
    ClassB.prototype.print.call(this);
    console.log("Sounds like this is working!");
}
 
var c = new ClassC();
c.print();

And the output is:

class C 
I'm the grandchild 
Sounds like this is working!

More Hands-on with JavaScript

It might surprise you a bit, but Microsoft has a bunch of free learning on many open source JavaScript topics and we’re on a mission to create a lot more with Project Spartan coming. Check out my own:


And some free tools: Visual Studio Community, Azure Trial, and cross-browser testing tools for Mac, Linux, or Windows.

Tuesday, April 07, 2015

CSS3 Multi-column Layouts

CSS3 Multi-column Layouts

The CSS multi-column layout uses new CSS properties which allow designers to break a layout into blocks. The two main properties which control the number of columns are: column-count and column-width.

Related Properties

  • column-width
  • column-count
  • column-gap
  • column-rule
  • column-rule-width
  • column-rule-style
  • column-rule-color
  • column-span
  • column-fill
  • columns

Degradation

Column properties are ignored by browsers which don't support them. To deal with that issue, create a single column layout for unsupported browsers and multiple columns with browsers that support them.

Note: To make sure you can use multiple columns, each property needs to be written three times: Once with the -moz prefix, once with the -webkit prefix, and once without the prefix.

Syntax

Here are some examples of how you would use the multi-column properties:

Here's how to use column-count:



Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut eu augue orci. Morbi tristique a felis et varius. Sed augue nunc, cursus sed congue sit amet, mollis sed risus. Aliquam sit amet fringilla nisl. Vivamus ullamcorper odio magna, ut sagittis justo accumsan at. Donec turpis turpis, sagittis vel nisl eget, sodales ullamcorper eros. Etiam ut velit non sapien tincidunt ultrices in et nisi.

You use the column-width property to set the smallest column width. If you don't set the column-count, the browser will take over and create as many columns as necessary to fit the width. Here's the code:



Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut eu augue orci. Morbi tristique a felis et varius. Sed augue nunc, cursus sed congue sit amet, mollis sed risus. Aliquam sit amet fringilla nisl. Vivamus ullamcorper odio magna, ut sagittis justo accumsan at. Donec turpis turpis, sagittis vel nisl eget, sodales ullamcorper eros. Etiam ut velit non sapien tincidunt ultrices in et nisi.

Here is an example which makes use of column-count, column-gap, and column-rule:


Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut eu augue orci. Morbi tristique a felis et varius. Sed augue nunc, cursus sed congue sit amet, mollis sed risus. Aliquam sit amet fringilla nisl. Vivamus ullamcorper odio magna, ut sagittis justo accumsan at. Donec turpis turpis, sagittis vel nisl eget, sodales ullamcorper eros. Etiam ut velit non sapien tincidunt ultrices in et nisi. Phasellus fringilla quam rutrum, semper neque pretium, fermentum justo. Suspendisse convallis, purus vitae mollis semper, est justo pretium neque, sit amet convallis nisi justo vel justo. Integer vestibulum, felis vel ultricies ornare, diam risus viverra odio, at tempus elit tellus quis purus. Sed porta, eros vel vehicula sollicitudin, nisi orci maximus magna, vitae commodo dui magna nec libero.

CSS3 Multi-column Layouts

Height Balancing

With the CSS3 Column specification the browser automatically sets the column height so the content in each column are similar. That said, you might want to set the height manually using the CSS height or max-height properties and then build your layout accordingly.

Resources