Showing posts with label layout. Show all posts
Showing posts with label layout. Show all posts

Sunday, December 20, 2015

6 Essential Bourbon Neat Mixins

6 Essential Bourbon Neat Mixins

This tutorial is aimed at getting you started with Neat; a semantic grid framework built for Sass and Bourbon.

Monday, October 19, 2015

Diamond grid layout with Sass

Diamond grid layout with Sass

Since I started my career on the web, I've been building websites that follow standard grid layouts. It got to a point where I was telling an intern at my company that developers think in rectangles. I mean, there's nothing wrong with rectangular layouts. They're like your mom's Volvo, steady and reliable. But sometimes, it's fun to try something different. I'm lucky enough to work with some awesome designers, and for a new project, they came up with a diamond-based grid layout. Well then, challenge accepted. (•̀o•́)ง

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


Sunday, September 28, 2014

All You Need To Know About Vertical-Align

Vertical-Align

Often I need to vertically align elements side by side.

CSS offers some possibilities. Sometimes I solve it with float, sometimes with position: absolute, sometimes even dirty by manually adding margins or paddings.

Saturday, May 24, 2014

Parallax Done Right

Parallax Done Right

Getting great performance with parallax is tough. Here's how to make it happen.

Tldr; There are an easy handful of things you can do to get buttery parallax scroll. Check out a demo I cooked up to see it in action.

Friday, January 24, 2014

Prevent common problems when writing CSS from scratch

Many times when I started writing the classes of a brand new site, I had two problems that bothered me very much: keeping the footer always at the bottom of the page - even if the page has few content - and using padding values in divs without influencing the overall width of the div.

Then I decided to always put the same basic classes on the css file, no matter what the layout would look like:

Friday, January 10, 2014

Sticky Table Headers & Columns

Sticky Table Headers & Columns

A tutorial on how to create sticky headers and columns for tables using jQuery. The solution is an alternative to other sticky table header approaches and it addresses the overflowing table problem including adding support for biaxial headers.

Sticky table headers are no longer a stranger to an average website user — unlike on paper when a reader's eyes can comfortably jump in saccades between top of a lengthy table and the rows of interest, the landscape orientation of most devices makes vertically-long tables hard to read. However, this very conundrum presents itself as a rich ground for UI experimentation that is not available to the printed media.

Sticky table headers, as their name implies, remains affixed to the top of the viewport even when the original table headers are scrolled out of view. They help to clarify the representation and purpose of data in columns when the visual reference to original table headers was lost. Besides that, the aid in orienting users in a sea of tabulated information, therefore avoiding the need to repeatedly and frustratingly, scroll between the top of the table where the header resides and the region of interest further down, typically lying out of the viewport.

There have been a handful of scripts and jQuery plugins written for the purpose of re-establishing the flow and ease of reading tables. While their implementation is flawless and efficient, they might not be an all-encompassing panacea for long tables. In some cases, tables have to obey certain layout rules that are not accounted for by the aforementioned plugins — such as tables that are forced to overflow due to dimension restrictions (e.g. to fit within a viewport).

While this tutorial does not try to serve as an all-encompassing panacea to the decidedly sticky problem with sticky table headers, it addresses more possible layout scenarios.

A Pure CSS-Based Solution with position: sticky?

Last September, a somewhat promising solution surfaced — a new possible value for the CSS position property is supported in the latest nightly build of WebKit or Chrome Canary. position: sticky sounded like a very promising new JS-free solution to the old and nuance problems of rigid table headers and beyond — its implementation can be also extremely useful in scenarios where a site navigation or a HTML5 app toolbar has to remain in view to the user at all times regardless of his/her scroll position along the document's y-axis.

Moreover, the sticky property value is supported in barely 6% of all global visits, making it a poor candidate for choice of implementation. Although it will not break layouts as browsers are dictated by W3C directive to ignore properties values that are unrecognized, invalid or illegal, it is not an ideal candidate when cross-browser functionality is desired.

The jQuery Based Solution

The jQuery-based solution is rather straight-forward. Before we move on with the JS itself, we should come to a common consensus how a semantically valid table should look like in the markup:

<table>
    <thead>
        <tr>
            <th></th>
            <!-- more columns are possible -->
    </tr>
    </thead>
    <tbody>
        <tr>
            <td></td>
            <!-- more columns are possible -->
        </tr>
        <!-- more rows are possible -->
    </tbody>
    <tfoot><!-- optional -->
        <tr>
            <td></td>
        </tr>
    </tfoot>
</table>

What do we want to achieve?

We should enumerate the expectations of this script. It would be great if the script can accommodate various table layouts and situations:

  • Basic usage: Sticky table header only
  • Biaxial table headers
  • Wide tables:
    • Horizontal overflow: If there is a row header, we should introduce a sticky table column, too
    • Vertical overflow: Covered in basic usage
    • Biaxial overflow: Introduce sticky table header and column

Some CSS groundwork

Despite choosing to work with a JS-based solution, we will still have to rely on CSS for the basic styling of the headers. The important things is that we have to position the sticky header absolutely within a common parent with its full-fledge, original table sibling. The CSS is rather straight forward:

.sticky-wrap {
    overflow-x: auto;
    position: relative;
    margin-bottom: 1.5em;
    width: 100%;
}
.sticky-wrap .sticky-thead,
.sticky-wrap .sticky-col,
.sticky-wrap .sticky-intersect {
    opacity: 0;
    position: absolute;
    top: 0;
    left: 0;
    transition: all .125s ease-in-out;
    z-index: 50;
    width: auto; /* Prevent table from stretching to full size */
}
    .sticky-wrap .sticky-thead {
        box-shadow: 0 0.25em 0.1em -0.1em rgba(0,0,0,.125);
        z-index: 100;
        width: 100%; /* Force stretch */
    }
    .sticky-wrap .sticky-intersect {
        opacity: 1;
        z-index: 150;
    }
    .sticky-wrap .sticky-intersect th {
        background-color: #666;
        color: #eee;
    }
.sticky-wrap td,
.sticky-wrap th {
    box-sizing: border-box;
}

Note: It is extremely important that you port the styles for your <table> elements over to .sticky-wrap. Although margins of pixel values can be easily calculated and applied to the new wrapper element, automatic margins are difficult to deal with (it is not possible to fetch the value of auto with jQuery in a straightforward manner) and it is easier if we simply apply the margins and width of tables to the wrapper element itself.

Let's say you have the following styles for your table:

table {
    margin: 0 auto 1.5em;
    width: 75%;
}

You can simply add the lines to ".sticky-wrap", too:

.sticky-wrap {
    overflow-x: auto; /* Allows wide tables to overflow its containing parent */
    position: relative;
    margin: 0 auto 1.5em;
    width: 75%;
}

I shall walk you through the steps that will, with a dozens of lines of JavaScript, create functional sticky table headers. For the ease of presentation, the script is presented in a logical flow towards problem solving — declaration of variables with the var statement can definitely be concatenated for a more compact and compressed script, but at the sake of logical flow and readability, therefore I have chosen not to adopt the latter approach.

We shall execute our function for every single instance of table selected for upon DOM ready. Moreover, we will also want to check if the selected tables contain the <thead> element and that the <thead> element is not empty and contains at least one <th> child. If the aforementioned criteria are not satisfied, our function will simply skip that instance of <table> and move on to the next.

$(function () {
    // Here we select for <table> elements universally,
    // but you can definitely fine tune your selector
    $('table').each(function () {
        if($(this).find('thead').length > 0 && $(this).find('th').length > 0) {
            // Rest of our script goes here
        }
    });
});

Step 1: Clone the <thead> element

Before we start, we will want to close the table head and declare some shorthand variables for ease of use:

// Declare variables and shorthands
    var $t     = $(this),
        $w     = $(window),
        $thead = $(this).find('thead').clone(),
        $col   = $(this).find('thead, tbody').clone();

Step 2: Wrap table and append new tables

In order to extend compatibility towards tables that have excessive width along the x-axis (e.g. having too many columns, or columns that are necessarily yet excessively wide), we wrap the table elements in a <div> element that is allowed to overflow along the x-axis. The width and margin properties are reset for the table so as to allow proper display within the wrapper.

// Wrap table
$t
.addClass('sticky-enabled')
.css({
    margin: 0,
    width: '100%';
})
.wrap('<div class="sticky-wrap" />');

// Check if table is set to overflow in the y-axis
if($t.hasClass('overflow-y')) $t.removeClass('overflow-y').parent().addClass('overflow-y');

// Create new sticky table head (basic)
$t.after('<table class="sticky-head" />')

// If <tbody> contains <th>, then we create sticky column and intersect (advanced)
if($t.find('tbody th').length > 0) {
    $t.after('<table class="sticky-col" /><table class="sticky-intersect" />');
}
// Create shorthand for things
var $stickyHead  = $(this).siblings('.sticky-thead'),
    $stickyCol   = $(this).siblings('.sticky-col'),
    $stickyInsct = $(this).siblings('.sticky-intersect'),
    $stickyWrap  = $(this).parent('.sticky-wrap');

Step 3: Inserting cloned table contents

The trick now is to insert contents cloned from our original table into the newly created tables that will serve as our sticky elements:

  1. Sticky header will receive all contents from the cloned <thead> element
  2. Sticky column will receive contents from the first <th> from <thead> and all the subsequent <th> from <tbody>. This is assuming that each row only contains one table header cell.
  3. Sticky intersect will receive content from the top left most cell in the table

// Sticky header gets all content from <thead>
$stickyHead.append($thead);

// Sticky column gets content from the first <th> of both <thead> and <tbody>
$stickyCol
.append($col)
    .find('thead th:gt(0)').remove()
    .end()
    .find('tbody td').remove();

// Sticky intersect gets content from the first <th> in <thead>
$stickyInsct.html('<thead><tr><th>'+$t.find('thead th:first-child').html()+'</th></tr></thead>');

Step 4: Functions

Here comes the most important part of our jQuery script — we decide what functions are needed for sticky headers to work and we declare them with the var statement to allow for easy callback. Two functions immediately come to mind:

  1. A function to determine the widths of individual <th> elements in the cloned header. Since we only cloned the <thead> element, the computed width of the cloned header will not be the same as the actual header itself, since the content of <tbody> itself, which may or may not influence the final width of each individual columns, is not included.
  2. A function to position the sticky header, so that we can update the vertical offset of the cloned header that is absolutely positioned when the scroll event is fired.
  3. A function to position the sticky column, so that we can update the horizontal offset when the parent element is overflowing.
  4. A function to calculate allowance — this feature is explained later in greater detail.

You may ask, why do I have to calculate the vertical offset of the header instead of simply using position: fixed? I, too, have contemplated over this issue, but it came to my realization that if we are allowing the table to overflow along the x-axis, the fixed positioning option has to go out of the window, because it will not scroll with the table in the event of a horizontal overflow.

// Function 1: setWidths()
// Purpose: To set width of individually cloned element
var setWidths = function () {
        $t
        .find('thead th').each(function (i) {
            $stickyHead.find('th').eq(i).width($(this).width());
        })
        .end()
        .find('tr').each(function (i) {
            $stickyCol.find('tr').eq(i).height($(this).height());
        });

        // Set width of sticky table head
        $stickyHead.width($t.width());

        // Set width of sticky table col
        $stickyCol.find('th').add($stickyInsct.find('th')).width($t.find('thead th').width())

    },
// Function 2: repositionStickyHead()
// Purpose: To position the cloned sticky header (always present) appropriately
    repositionStickyHead = function () {
        // Return value of calculated allowance
        var allowance = calcAllowance();

        // Check if wrapper parent is overflowing along the y-axis
        if($t.height() > $stickyWrap.height()) {
            // If it is overflowing
            // Position sticky header based on wrapper's scrollTop()
            if($stickyWrap.scrollTop() > 0) {
                // When top of wrapping parent is out of view
                $stickyHead.add($stickyInsct).css({
                    opacity: 1,
                    top: $stickyWrap.scrollTop()
                });
            } else {
                // When top of wrapping parent is in view
                $stickyHead.add($stickyInsct).css({
                    opacity: 0,
                    top: 0
                });
            }
        } else {
            // If it is not overflowing (basic layout)
            // Position sticky header based on viewport scrollTop()
            if($w.scrollTop() > $t.offset().top && $w.scrollTop() < $t.offset().top + $t.outerHeight() - allowance) {                 // When top of viewport is within the table, and we set an allowance later
                // Action: Show sticky header and intersect, and set top to the right value
                $stickyHead.add($sticktInsct).css({
                    opacity: 1,
                   top: $w.scrollTop() - $t.offset().top
                });
             } else {
                 // When top of viewport is above or below table
                 // Action: Hide sticky header and intersect
                 $sticky.add($stickInsct).css({
                     opacity: 0,
                     top: 0
                 });
             }
        }
    },
// Function 3: repositionStickyCol()
// Purpose: To position the cloned sticky column (if present) appropriately
    repositionStickyCol = function () {
        if($stickyWrap.scrollLeft() > 0) {
            // When left of wrapping parent is out of view
            // Show sticky column and intersect
            $stickyCol.add($stickyInsct).css({
                opacity: 1,
                left: $stickyWrap.scrollLeft()
            });
        } else {
            // When left of wrapping parent is in view
            // Hide sticky column but not the intersect
            // Reset left position
            $stickyCol
            .css({ opacity: 0 })
            .add($stickyInsct).css({ left: 0 });
        }
    },
// Function 4: calcAllowance()
// Purpose: Return value of calculated allowance
     calcAllowance = function () {
         var a = 0;

         // Get sum of height of last three rows
         $t.find('tbody tr:lt(3)').each(function () {
             a += $(this).height();
         });

         // Set fail safe limit (last three row might be too tall)
         // Set arbitrary limit at 0.25 of viewport height, or you can use an arbitrary pixel value
         if(a > $w.height()*0.25) {
            a = $w.height()*0.25;
        }

        // Add height of sticky header itself
        a += $sticky.height();

        return a;
    };
}

Now, you may ask, what is allowance? What do we need it for? The basis of the allowance is simple — we do not want the sticky table header to follow us all the way to the end of the table, do we? It is unnecessary and run the risk of obfuscating the last table row. While this feature is optional (thus allowance is set to 0, see above), I highly recommend allowing at least one table row of height remaining. The height can be computed from the table itself, or you can set a fixed height.

As far as my experience go, I realize that I do not need the header much after the last three rows of the table is shown — that is because by then our eyes would have probably moved away from the table into the content below. This threshold is arbitrary and it is up to you to decide.

// Calculate allowance
// We allow the last three rows to be shown without the need for the sticky header to remain visible
$t.find('tbody tr:lt(4)').each(function () {
    allowance += $(this).height();
});

Step 5: Fire away, fire away!

Now we are done declaring all the functions we need for the correct styling and positioning of the sticky header. All is left is to bind event handlers to the $(window) object (previously abbreviated as $w for your convenience) and trigger the right function. Here is the game plan:

  1. When the DOM is ready, perform initial round of width calculations
  2. When all resources are loaded, perform second round of width calculations. This is important especially when your table contains resources that are loaded after DOM ready event, such as images, @font-face and more, which will influence how table column widths are computed.
  3. When the parent wrapper is scrolled, but this only happens if the content is overflowing. In the event of a scrolling event is detected, we want to reposition the sticky column
  4. When the viewport is resized, we want to recompute widths and reposition the sticky header
  5. When the window is scrolled, we want to reposition the sticky header

This can be easily summarized with the code below. Do note that the resize and scroll events are debounced and throttled respectively using Bel Alman's jQuery throttle+debounce plugin.

// #1: When DOM is ready (remember, we have wrapped this entire script in $(function(){...});
setWidths();

// #2: Listen to scrolling event on the parent wrapper (will fire if there is an overflow)
$t.parent('.sticky-wrap').scroll($.throttle(250, function() {
    repositionStickyHead();
    repositionStickyCol();
}));

// Now we bind events to the $(window) object
$w
// #3: When all resources are loaded
.load(setWidths)
// #4: When viewport is resized
// (we debounce this so successive resize event is coalesced into one event)
.resize($.throttle(250, function () {
    setWidths();
    repositionStickyHead();
    repositionStickyCol();
})
// #5: When the window is scrolled
// (we throttled this so scroll event is not fired too often)
.scroll($.throttle(250, repositionStickyHead);

And voila, you're done!

Discussion

No tutorial is complete without a discussion — be it addressing potential drawbacks on the technicalities of implementation, or the explanation of my strategy in contrary to common expectations.

Why don't you use position: fixed?

Fixed positioning is a very tantalizing alternative, mainly because of the two advantages it confers:

  1. No calculations are needed for the sticky table header's vertical offset, because fixed position will cause the element to be positioned absolutely within the viewport and out of the document flow.
  2. Avoids the stuttering effect of the sticky table header playing catch up, as the scroll event is throttled and therefore the calculations are performed at fixed time intervals and not on the fly. It may appear less responsive to user movement and therefore less natural.

However, the issue with fixed positioning is that we are effectively removing the element from the document flow. In the event when the table width exceeds that of its containing and a horizontal overflow is absolutely necessary, the fixed position header will not scroll with the table because it is detached from the document layout. This is one of the major drawbacks with many jQuery plugins out there that offers sticky table header functionality and this tutorial was written partially to address this issue.

Why don't you use position: sticky?

The new position attribute, position: sticky, is only available to the latest version of WebKit browsers and require vendor prefixes. It is not supported in Firefox, Internet Explorer and Opera, therefore risking alienating a huge user base (~95%) due to lack of support. It is not official and standardized as of yet, so I would rather err on the side of caution and choose a more cumbersome but cross-browser friendly JS-based solution.

View Demo

Monday, November 04, 2013

Using CSS Shapes to Enhance Visual Storytelling

CSS Shapes to  Enhance Visual Storytelling

Web designers have long been forced to create within the constraints of blocks. Since most daring ventures into non-rectangular layouts using regular CSS and HTML usually end in frustration, most of the content on the web is still trapped in simple boxes.

Saturday, October 05, 2013

A collection of separator styles

A collection of separator styles

A collection of separator styles for horizontally dividing sections on a website. The dividers are created using several techniques, including styling pseudo-elements, using gradients and inserting SVG graphics with responsiveness in mind.

Friday, August 23, 2013

Responsive Content Using CSS Regions

Responsive Content Using CSS Regions

CSS Regions allow content to flow across multiple areas of the display, called regions.  The beauty of CSS Regions is that you can separate the content from the layout. And with that comes the ability to create some responsive content very easily.

Friday, August 09, 2013

Create an Awesome Single-Page Website

Create an Awesome Single-Page Website

Not every website needs to be complex or include multiple pages of content and information.

Sometimes one page is enough.

But just because you are creating a website with only one page, does not mean that it will be easy.

Developing a single-page layout can require just as much thought and planning as some more complex sites. It needs to have all the same basic parts as a bigger site and should look visually stunning, work as expected and have a clear purpose.

Thursday, July 11, 2013

CSS3 Multiple Column Layout Module

CSS3 Multiple Column Layout Module

The Multi Column Layout Module has been introduced to help us create columns quickly and easily using CSS3 only. In this tut I'm going to be taking a look at some of its properties and demonstrate them through a series of examples.

Saturday, June 08, 2013

Text-align: Justify and RWD

Text-align: Justify and RWD

Did you know that one of the most powerful tools for fluid and responsive layout has been a native feature for every browser since HTML 4?

Thursday, April 25, 2013

Customize an HTML5 Webpage using the Bootstrap Framework

Bootstrap Framework
Many web developers are familiar with Twitter Bootstrap and have seen this library on a number of projects. The Bootstrap core is fantastic when you need a CSS reset along with other common layout features. It may not be the right fit on projects where you need a whole lot of customization. But for landing pages and smaller websites I think Bootstrap has become one of the easiest resources to start using.

Tuesday, April 09, 2013

6 Problems Hindering Responsive Web Designing With Solutions

Problems Hindering Responsive Web Designing With Solutions
The emerging trend of using internet through Smartphones is making web designers think about responsive web designing. However, there are several problems that web designers have to encounter while creating such designs. The problems usually occur in the technical areas. Some common RWB problems that web designers face along with solution are given in the lines below.

Wednesday, April 03, 2013

Create An Interactive Metro Style Grid Dashboard

Metro Style Grid Dashboard

Since Windows 8 released it's first pictures of the new design, people have been going crazy over the metro style. People love it, it's modern, it's clean, it's simple and makes it really easy to use on mobile devices, especially on tablet devices.

Saturday, March 16, 2013

The pro's guide to CSS layouts

CSS layouts

CSS's next big challenge is to make flexible, dynamic page layouts that work across our ever-broadening range of devices. With solutions proposed and under discussion, Peter Gasston offers a snapshot of the future.

Tuesday, February 19, 2013

Responsive, Horizontal Multi-Column Layouts

Responsive, Horizontal Multi-Column Layouts

The problem with responsive multiple columns

When the multiple column syntax was first introduced, I was hopelessly optimistic about the possibilities that this new layout technique would offer us in crafting good reading experiences.

Friday, December 21, 2012

Giving content priority with CSS3 grid layout

Giving content priority with CSS3 grid layout

Browser support for many of the modules that are part of CSS3, have enabled us to use CSS for many of the things we used to have to use images for. The rise of mobile browsers and the concept of responsive web design has given us a whole new way of looking at design for the web. However, when it comes to layout, we haven't moved very far at all. We have talked for years about separating our content and source order from the presentation of that content, yet most of us have had to make decisions on source order in order to get a certain visual layout.