SEO Werkt!

Seo werkt!

Archive for the ‘div’ tag

Simulating The Letterpress: From Live Filters In Fireworks To CSS Code

without comments




  

One of the visual effects that is a mainstay in my Web design toolkit is the letterpress effect. Used properly, it’s a quick way to make text blend better with the layout, as if it were machine-stamped onto the background. Think of what a home appliance marquee or a professional business card looks (and feels) like, and you’ll know what I’m talking about.

I’ve developed a simple workflow for creating a letterpress text effect in Adobe Fireworks that, with the advent of CSS3, can be applied directly to HTML text — no images needed. Here’s the best part: it doesn’t use any Bevel or Emboss Live Filters.

What Is Letterpress?

Letterpress is a venerable technique of printing that involves “pressing” a plate of movable type onto a sheet of paper to produce an effect that is impressed (where the text is pressed down onto the paper) or embossed (where the text is raised above the surface of the paper).


An example of a letterpress business card with impressed text. (Image: Audimas Adomavicious)

The classic charm of letterpress found its place in digital design once designers were able to emulate its effect on screen. To accomplish that, designers observed the effect of light and shadow on the dents on paper that had gone through the printing process. Imagine a light shining down at an angle on a sheet of letterpress text. Impressed text will appear to have a sliver of highlighting at the bottom edge of the letters and a thin shadow at the top edge. Embossed text is just the opposite: highlights on top, shadows on the bottom. These properties create the effect of raised or sunken areas along the surface, and this can be translated using effects made possible by both Fireworks and the CSS3 specification.

Why Not Just Use Bevel or Emboss?

Fireworks’ Bevel and Emboss Live Filters are a bit primitive for my tastes. The refinement controls are unwieldy — for example, you can’t set highlights and shadows independently — and the result is subpar. It works OK for straight edges and sharp corners, but it gets rough around curves. I suspect this is because the effect is raster-based, so that it can work with any object (shape, text or embedded image); a vector-based tool would have allowed for a smoother and more precise effect.


The letterpress effect using the Outer Bevel Live Filter. Notice the roughness of the curved edges.

Letterpress Text In Fireworks

A better way to recreate the effect would be to use the Drop Shadow Live Filter, because it produces smoother edges. This solution hinges on a basic setting: a shadow and a highlight, offset exactly 1 pixel up or down, relative to the text object. For this tutorial, we’ll start with two text objects of different colors, set against a colored background.


Start with two text objects.

Embossed Text

To create an embossed effect, apply two Drop Shadow Live Filters to our first text object:

  • Apply a “Shadow” (distance: 1; color: #000000; opacity: 60%; blur: 0; angle: 270;) to the bottom of the text, and
  • Apply a “Highlight” (distance: 1; color: #FFFFFF; opacity: 90%; blur: 0; angle: 90;) to the top of the text.


Embossed effect applied to the “Smashing” text object.

The opacity of the Drop Shadow filters will depend on how light or dark the background is in relation to the text’s color. Tweak these values according to how pronounced you want the letterpress effect to be.


Adjust the opacity value in the Drop Shadow Live Filter.

Impressed Text

To create an impressed effect for the second text object, just switch the angle values of the “Shadow” and “Highlight” Drop Shadow filters shown in the previous step, so that the shadow is on top of the text and the highlight is on the bottom. Adjust the opacity values to maintain contrast against the darker text object’s color.


Impressed effect applied to the “Magazine” text object.

Note: These effects work best with text and background color combinations that aren’t black and white, as in our example. If you’re working with black text or black backgrounds, you’ll want to skip the “Shadow” effect, because it will do little for the text. Similarly, for white text or white backgrounds, forego the “Highlight” effect.

Save as Style for Reuse

Now that our letterpress effects are in place, we can save them as Fireworks Styles so that we can use them again later without having to apply each filter manually.

To create a Fireworks Style:

  1. Select the “Smashing” text object with the Pointer tool (V);
  2. Bring up the Styles panel (Control/Command + F11, or in the menu Window → Styles);
  3. Click on the context-menu icon in the top-right corner of the panel, and click on “New Style”;
  4. In the “New Style” dialog box, let’s give our style a descriptive name, like “Letterpress Emboss.” Uncheck all properties except for “Effect,” and click OK.
  5. Repeat steps 1 to 4 for the “Magazine” text object.


Styles panel and context menu


“New Style” dialog box

You should now see two new items in your Styles panel. The next time you want to apply the emboss or impress effect to a text object, just select that object, and click on the new style that you created.


Styles panel with two new styles

Additionally, you can save these new styles as a Style Library file (*.stl), to share with other designers or to back up your styles before reinstalling Fireworks.

To save a set of styles as a Style Library file:

  1. Bring up the Styles panel (Control/Command + F11, or Window → Styles);
  2. Click on the context-menu icon in the top-right corner of the panel, and click “Save Style Library”;
  3. In the “Save As” dialog box, enter a descriptive file name for the STL file, and then click “Save.”


The Styles panel, again.


“Save As” dialog box

To import a previously saved Style Library:

  1. Bring up the Styles panel (Control/Command + F11, or Window → Styles);
  2. Click on the context-menu icon in the top-right corner of the panel, and click “Import Style Library”;
  3. In the “Open” dialog box, browse to and select the STL file, and then click “Open.”

Hint: Need a good library of Letterpress Styles for Adobe Fireworks? Why not check this 16 Letterpress Styles set by Mikko Vartio?

Translating Into CSS

Option 1: Translate the Values of the Live Filters Manually

Aside from the downsides of the Bevel and Emboss filters that I mentioned earlier, the other reason I use Drop Shadow filters is that they readily translate into CSS3’s text-shadow property. Consider this basic syntax:

text-shadow: [x-offset] [y-offset] [blur] [color-alpha];

Let’s break this down:

  • [x-offset] is set to 0, and [y-offset] is either 1px or -1px, depending on whether the shadow or highlight is at the top (90°) or bottom (270°);
  • [blur] is set to 0, to keep the shadow and highlight effects crisp;
  • [color-alpha] is set using an RGBa value: rgba(r, g, b, a).
    • The first three values (rg and b) correspond to the decimal red-green-blue values of the color itself (for example, #FFFFFF in hexadecimal is equal to 255, 255, 255 in decimal);
    • The last value (a) determines the transparency of the color (where 0 is completely transparent, 0.5 is half-transparent, and 1 is completely opaque).

Let’s apply our effects to the following HTML markup:

<div class="embossed">Smashing</div>
<div class="impressed">Magazine</div>

Our CSS for the embossed effect would be:

div.embossed {
   text-shadow:
      0 1px 0 rgba(0, 0, 0, 0.8), /* shadow */
      0 -1px 0 rgba(255, 255, 255, 1.0); /* highlight */ }

And for the impressed effect:

div.impressed {
   text-shadow:
      0 -1px 0 rgba(0, 0, 0, 0.8), /* shadow */
      0 1px 0 rgba(255, 255, 255, 0.5); /* highlight */ }

Here, I have slightly adjusted the opacity values in the text-shadow property (relative to the original values in the Drop Shadow Live Filter in Fireworks) to better suit the way fonts are rendered in the browser.


Screenshot of the HTML and CSS output in Mozilla Firefox. See an HTML sample.


Screenshot of the HTML and CSS output in Apple Safari. See an HTML sample.

Option 2: Use the CSS Properties Panel in Fireworks CS6

Writing CSS code by hand is what we Web professionals usually do. But in some cases, tools can help us, too.

Fireworks CS6 (which was recently released) has a new feature that could help you when you want to quickly (yet reliably) translate the properties of a visual element in the design to CSS3 code. The CSS Properties panel can extract CSS3 code for virtually any object selected on the canvas, including text objects and live filters.

Let’s see how this could help us in practice when working with the letterpress effect!

If you have a copy of Fireworks CS6 (a trial version would do, too), open the letterpress-effect.fw.png file provided with this tutorial (see the Downloads section further below), and then with the Selection tool, select the first text object.


Open the letterpress-effect.fw.png file, and select the first text object.

Next, open the CSS Properties panel (in the menu, Window → CSS Properties, or Control/Command + F7), and while the first text object is selected, notice how the CSS panel instantly shows the object’s properties.


The CSS Properties panel shows the properties of the selected text object as CSS code. Highlighted here is the code that translates the two Live Filters into CSS.

In this case, we’re interested only in the Live Filters applied to the text object, so let’s copy this bit of code from the CSS panel and see how it looks:

text-shadow: 0 1px 0 rgba(0,0,0,0.6), 0 -1px 0 rgba(255,255,255,0.9);

As you see, we’ve got results similar to what we achieved earlier with the manual method. Fireworks CS6 has automatically translated the Live Filters that were applied to the “embossed” text object into clean and valid CSS!

Similarly, you can extract and copy the CSS for the Live Filters applied to the “impressed” text effect.

And if you strive for perfection (as many of us do), along with the CSS Properties panel, you can use CSS Professionalzr, an excellent free extension by Matt Stow that can further optimize the code produced by the CSS Properties panel.

Of course, even if you’ve already switched to Fireworks CS6, you can always opt to translate the properties of Live Filters to CSS code manually. But when you’re dealing with a lot of objects, the CSS Properties panel comes in really handy and can save you precious time.

Tips on Using the Letterpress Effect

  • Use the effects sparingly.
    Text effects are the last thing you want to abuse, because they could impair readability, especially for people with vision problems. Restrict them to headings and interactive items (such as buttons and menu links).
  • Enable them to degrade gracefully.
    While most modern browsers already support CSS3 to some extent (see the note below), Internet Explorer 9 still doesn’t recognize the text-shadow property. In an effort to make things look consistent, you might want to look for a workaround, but I highly recommend that you gracefully degrade the effect in browsers that don’t support the property. Effects should be enhancements, not vital features.

Please note: Browsers that fully support the text-shadow property (with multiple shadows) include Firefox 3.5+, Chrome 4+, Safari 4+ and Opera 9.5. As of version 9, Internet Explorer still does not support the official text-shadow definition; instead, it has a proprietary filter that achieves a similar effect.

Examples

Here are a few real-world examples of the letterpress effect in action.

Veerle’s Blog
The letterpress effect — applied to the (image-rendered) logotype and headings — creates a bit of contrast against the background here, while still keeping everything subtle. Notice the use of both embossed and impressed effects in the column headings.

Stunning CSS3 (teaser page)
Coupled with @font-face declarations for custom HTML fonts, the letterpress effect on the different heading levels makes for a sophisticated look, previously feasible only with image-based text. (Note that the teaser page we’ve linked to here is an archived version.)

Janko at Warp Speed
The use of only one text-shadow effect, and only on the headings, exemplifies Janko’s restraint in order to maintain contrast and readability. Also notice the 45° offset in the highlight effect, which you can achieve in CSS by adding a 1-pixel x-offset to the text-shadow.

Downloads

The samples (i.e. the Fireworks PNG and Style Library) should work fine in any recent version of Fireworks (CS4, CS5, CS5.1, CS6).

(al) (mb)


© Jose Olarte for Smashing Magazine, 2012.

Written by Jose Olarte

July 23rd, 2012 at 8:36 am

JavaScript Profiling With The Chrome Developer Tools

without comments




  

Your website works. Now let’s make it work faster. Website performance is about two things: how fast the page loads, and how fast the code on it runs. Plenty of services will make your website load faster, from minimizers to CDNs, but making it run faster is up to you.

Little changes in your code can have gigantic performance impacts. A few lines here or there could mean the difference between a blazingly fast website and the dreaded “Unresponsive Script” dialog. This article shows you a few ways to find those lines of code with Chrome Developer Tools.

Establish A Baseline

We’ll look at a simple application called a color sorter, which presents a grid of rainbow colors that you can drag and drop to mix up. Each dot is a div tag with a little CSS to make it look like a circle.

The Color Sorter

Generating my rainbow colors was a little tricky, so I got a little help from “Making Annoying Rainbows in JavaScript.”

The page loads pretty fast, but it still takes a moment and blinks a little before it paints. Time to profile the page and make it faster.

Always start performance-improvement projects with a baseline understanding of how fast or slow your application already is. The baseline will let you know whether you’re making improvements and help you make tradeoffs. For this article, we’ll use Chrome Developer Tools.

The profiler is part of Chrome Developer Tools, which is always available in Chrome. Click the “Tools” menu under the little wrench to open it. Firebug has some profiling tools, too, but the WebKit browsers (Chrome and Safari) are best at profiling code and showing timelines. Chrome also offers an excellent tool for event tracing, called Speed Tracer.

To establish our baseline, we’ll start recording in the “Timeline” tab, load our page and then stop the recording. (To start recording once Chrome Developer Tools is open, click the “Timeline” tab, and then the small black circle icon for “Record” at the very bottom of the window.) Chrome is smart about not starting to record until the page starts to load. I run it three times and take the average, in case my computer runs slowly during the first test.

Performance baseline 1

My average baseline — i.e. the time between the first request for the page and the final painting of the page in the browser — is 1.25 seconds. That’s not bad, but it’s not great for such a small page.

I want to make my code run faster, but I’m not sure what’s making it slow. The profiler helps me find out.

Create A Profile

The timeline tells us how long our code took to run, but that doesn’t help us know what’s going on while it’s running. We could make changes and run the timeline again and again, but that’s just shooting in the dark. The “Profiles” tab gives us a better way to see what’s going on.

Profilers show us which functions take the most time. Let’s make our baseline profile by switching to the “Profiles” tab in Chrome Developer Tools, where three types of profiling are offered:

  1. JavaScript CPU profile
    Shows how much CPU time our JavaScript is taking.
  2. CSS selector profile
    Shows how much CPU time is spent processing CSS selectors.
  3. Heap snapshot
    Shows how memory is being used by our JavaScript objects.

We want to make our JavaScript run faster, so we’ll use the CPU profiling. We start the profile, refresh the page and then stop the profiler.

The first profile

The first thing that’s clear from the profile is that a lot is going on. The color sorter uses jQuery and jQuery UI, which are doing a lot of stuff like managing plugins and parsing regular expressions. I can also see that two of my functions are at the top of the list: decimalToHex and makeColorSorter. These two functions take a total of 13.2% of my CPU time, so they’re a good place to start making improvements.

We can click the arrow next to the function calls to open the complete function-call stack. Expanding them, I see that decimalToHex is called from makeColorSorter, and makeColorSorter is called from $(document).ready.

Here’s the code:

$(document).ready(function() {
    makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127, 121);
    makeSortable();
});

Knowing where they’re called from also makes clear that making the colors sortable isn’t my biggest performance problem. Performance issues resulting from the addition of a lot of sortables is common, but my code is taking more time to add DOM elements than to make them sortable.

I want to start making those functions faster, but first I want to isolate my changes. A lot happens when the page loads, and I want to get all of that out of my profile.

Isolate The Problem

Instead of loading the color sorter when the document is ready, I’ll make a second version that waits until I press a button to load the color sorter. This isolates it from the document loading and helps me profile just the code. I can change it back once I’m done tuning performance.

Let’s call the new function testColorSorter and bind it to a clickable button:

function testColorSorter() {
    makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127, 121);
    makeSortable();
}
<button id="clickMe" onclick="testColorSorter();">Click me</button>

Changing the application before we profile could alter the performance of the application unexpectedly. This change looks pretty safe, but I still want to run the profiler again to see whether I’ve accidentally changed anything else. I’ll create this new profile by starting the profiler, pressing the button in the app and then stopping the profile.

The second profile

The first thing to notice is that the decimalToHex function is now taking up 4.23% of the time to load; it’s what the code spends the most time on. Let’s create a new baseline to see how much the code improves in this scenario.

The second baseline

A few events occur before I press the button, but I only care about how long it took between the times the mouse was clicked and the browser painted the color sorter. The mouse button was clicked at 390 milliseconds, and the paint event happened at 726 milliseconds; 726 minus 390 equals my baseline of 336 milliseconds. Just as with the first baseline, I ran it three times and took the average time.

At this point, I know where to look and how long the code takes to run. Now we’re ready to start fixing the problem.

Make It Faster

The profiler only tells us which function is causing the problem, so we need to look into it and understand what it does.

function decimalToHex(d) {
    var hex = Number(d).toString(16);
    hex = "00".substr(0, 2 - hex.length) + hex; 

    console.log('converting ' + d + ' to ' + hex);
    return hex;
}

Each dot in the color sorter takes a background color value in hex format, such as #86F01B or #2456FE. These values represent the red, green and blue values of the color. For example, Blue dot has a background color of #2456FE, which means a red value of 36, a green value of 86 and a blue value of 254. Each value must be between 0 and 255.

The decimalToHex function converts these RGB colors to hex colors that we can use on the page.

The function is pretty simple, but I’ve left a console.log message in there, which is just some debugging code we can remove.

The decimalToHex function also adds padding to the beginning of the number. This is important because some base-10 numbers result in a single hex digit; 12 in base 10 is C in hex, but CSS requires two digits. We can make the conversion faster by making it a little less generic. I know that the numbers to be padded each have one digit, so we can rewrite the function like this:

function decimalToHex(d) {
    var hex = Number(d).toString(16);
    return hex.length === 1 ? '0' + hex : hex; }

Version three of the color sorter changes the string only when it needs the padding and doesn’t have to call substr. With this new function, our runtime is 137 milliseconds. By profiling the code again, I can see that the decimalToHex function now takes only 0.04% of the total time — putting it way down the list.

The third profile

We can also see that the function using the most CPU is e.extend.merge from jQuery. I’m not sure what that function does because the code is minimized. I could add the development version of jQuery, but I can see that the function is getting called from makeColorSorter, so let’s make that one faster next.

Minimize Content Changes

The rainbow colors in the color sorter are generated from a sine wave. The code looks at a center point in the color spectrum and creates a wave through that center point over a specified width. This changes the colors into a rainbow pattern. We can also change the colors in the rainbow by changing the frequency of the red, green and blue.

function makeColorSorter(frequency1, frequency2, frequency3,
                         phase1, phase2, phase3,
                         center, width, len) {

    for (var i = 0; i < len; ++i)
    {
       var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center);
       var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center);
       var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center);

       console.log('red: ' + decimalToHex(red));
       console.log('green: ' + decimalToHex(green));
       console.log('blue: ' + decimalToHex(blue));

       var div = $('<div class="colorBlock"></div>');
       div.css('background-color', '#' + decimalToHex(red) + decimalToHex(green) + decimalToHex(blue));
       $('#colors').append(div);

    }
}

We could take out more console.log functions. The calls are especially bad because each is also calling the decimalToHex function, which means that decimalToHex is effectively being called twice as often as it should.

This function changes the DOM a lot. Every time the loop runs, it adds a new div to the colors div tag. This makes me wonder whether that’s what the e.extend.merge function was doing. The profiler makes it easy to tell with a simple experiment.

Instead of adding a new div each time the loop runs, I want to add all of the div tags at once. Let’s create a variable to hold them, and then add them once at the end.

function makeColorSorter(frequency1, frequency2, frequency3,
                         phase1, phase2, phase3,
                         center, width, len) {

    var colors = "";
    for (var i = 0; i < len; ++i)
    {
       var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center);
       var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center);
       var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center);

       colors += '<div class="colorBlock" style="background-color: #' +
           decimalToHex(red) + decimalToHex(green) + decimalToHex(blue) + '"></div>';
    }

    $('#colors').append(colors);
}

This small change in the code means that the DOM changes once, when it adds all of the div tags. Testing that with the timeline, we see that the runtime between the click and the paint events is now 31 milliseconds. This one DOM change has brought the time for version four down by about 87%. We can also run the profiler again and see that the e.extend.merge function now takes up such a small percentage of the time that it doesn’t show up on the list.

We could make the code one notch faster by removing the decimalToHex function entirely. CSS supports RGB colors, so we don’t need to convert them to hex. Now we can write our makeColorSorter function like this:

function makeColorSorter(frequency1, frequency2, frequency3,
                         phase1, phase2, phase3,
                         center, width, len) {

    var colors = "";
    for (var i = 0; i < len; ++i)
    {
       var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center);
       var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center);
       var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center);

       colors += '<div class="colorBlock" style="background-color: rgb(' +
           red + ',' + green + ',' + blue + ')"></div>';
    }

    $('#colors').append(colors);
}

Version five runs in only 26 milliseconds and uses 18 lines of code for what used to take 28 lines.

JavaScript Profiling In Your Application

Real-world applications are much more complex than this color sorter, but profiling them follows the same basic steps:

  1. Establish a baseline so that you know where you’re starting from.
  2. Isolate the problem from any other code running in the application.
  3. Make it faster in a controlled environment, with frequent timelines and profiles.

There are a few other rules to follow when tuning performance:

  1. Start with the slowest parts first so that you get the most improvement for the time spent tuning.
  2. Control the environment. If you switch computers or make any other major changes, always run a new baseline.
  3. Repeat the analysis to prevent anomalies on your computer from skewing the results.

Everyone wants their website to run faster. You have to develop new features, but new features usually make a website run slower. So, investing time in tuning the performance does pay off.

Profiling and tuning cut the final color sorter’s runtime by over 92%. How much faster could your website be?

(al) (km)


© Zack Grossbart for Smashing Magazine, 2012.

Written by Zack Grossbart

June 12th, 2012 at 12:54 pm

A Pure CSS3 Cycling Slideshow

without comments




  

Thanks to CSS3, we can create effects and animations without using JavaScript, which will facilitate the work of many designers.

But we must be careful to avoid abusing CSS3, not only because old browsers do not support all of its properties. In any case, we all see the potential of CSS3, and in this article we’ll discuss how to create an infinitely looping slider of images using only CSS3 animation.

Sections of This Article

To get a solid sense of the process from beginning to end, below is an outline of the article. Please note that this effect will only work properly in modern browsers that support the CSS3 properties being used.

  1. Introduction
    Learn basic concepts related to CSS3 transitions and keyframe animation.
  2. HTML markup
    Create the HTML markup for the sliding images.
  3. CSS styles
    Create the style sheet to display the slider.
  4. CSS3 keyframe animation
    Add animation to the slider (we’ll explain the various processes happening here).
  5. Progress bar
    Add a progress bar for our slider.
  6. Tooltip
    Add a tooltip to display the title of the image.
  7. CSS3 transitions
    Animate the tooltip using CSS3 transitions to make it appear to hover over the image.
  8. Pause and restart
    Pause the slider and restart it on hover.
  9. Demo
    Check out the slider in action.
  10. Conclusion
    Final considerations.

Pure CSS3 Cycle Slider
Screenshot of the pure CSS3 cycling slideshow.

1. Introduction

To follow this tutorial, having a basic understanding of CSS, especially CSS3 transitions and keyframe animation, is important. Using this simple concept, we will see how to make a functional image slider.

Basic Concepts of CSS3 Transitions

Normally when you change a CSS value, the change is instant. Now, thanks to the transition property, we can easily animate from the old to new state.

We can use four transition properties:

  1. transition-property
    Defines the name(s) of the CSS properties to which the transitions should be applied.
  2. transition-duration
    Defines the duration over which the transitions should occur.
  3. transition-timing-function
    Determines how intermediate values of the transition are calculated. The effects from the timing function are commonly called easing functions.
  4. transition-delay
    Defines when the transition starts.

At the moment, CSS3 transitions are supported in Safari 3.2+, Chrome, Firefox 4+, Opera 10.5+ and IE 10. Because the technology is still relatively new, prefixes for browsers are required. So far, the syntax is exactly the same for each browser, with only a prefix change required. We will omit them in the snippets in this article, but please remember to include the prefixes in your code.

Let’s see how to apply a simple transition to a link:

a {
   color: #000;
   transition-property: color;
   transition-duration: 0.7s;
   transition-timing-function: ease-in;
   transition-delay: 0.3s;
}

a:hover {
   color: #fff;
}

When assigning an animation to an element, you can also use the shorthand:

a  {
   color: #000;
   transition: color 0.7s ease-in 0.3s;
}

a:hover {
   color: #fff;
}

The W3C has a list of all “Animatable Properties.”

Basic Concepts of CSS3 Animations

CSS animation enables us to create animations without JavaScript by using a set of keyframes.

Unlike CSS transitions, keyframe animations are currently supported only in Webkit browsers and Firefox and soon in IE 10. Unsupported browsers will simply ignore your animation code.

The animation property has eight subproperties:

  1. animation-delay
    Defines when the animation starts.
  2. animation-direction
    Sets the animation to play in reverse on alternate cycles.
  3. animation-duration
    Defines the length of time an animation takes to complete one cycle.
  4. animation-iteration-count
    Defines the number of times an animation cycle should play before stopping.
  5. animation-name
    Specifies the name of the @keyframes rule.
  6. animation-play-state
    Determines whether an animation is running or paused.
  7. animation-timing-function
    Describes how an animation progresses over one cycle.
  8. animation-fill-mode
    Specifies how a CSS animation should apply styles to its target before and after executing.

Let’s see how to apply a simple animation to a div.

/* This is the element we are applying the animation to. */

div {
   animation-name: move;
   animation-duration: 1s;
   animation-timing-function: ease-in-out;
   animation-delay: 0.5s;
   animation-iteration-count: 2;
   animation-direction: alternate;

   -moz-animation-name: move;
   -moz-animation-duration: 1s;
   -moz-animation-timing-function: ease-in-out;
   -moz-animation-delay: 0.5s;
   -moz-animation-iteration-count: 2;
   -moz-animation-direction: alternate;

   -webkit-animation-name: move;
   -webkit-animation-duration: 1s;
   -webkit-animation-timing-function: ease-in-out;
   -webkit-animation-delay: 0.5s;
   -webkit-animation-iteration-count: 2;
   -webkit-animation-direction: alternate;
}

/* This is the animation code. */

@keyframes move {
   from {
      transform: translateX(0);
   }
   to {
      transform: translateX(100px);
   }
}

@-moz-keyframes move {
   from {
      -moz-transform: translateX(0);
   }
   to {
      -moz-transform: translateX(100px);
   }
}

@-webkit-keyframes move {
   from {
      -webkit-transform: translateX(0);
   }
   to {
      -webkit-transform: translateX(100px);
   }
}

But we can use the shorthand property to conveniently set all of the animation properties at once.

div {
   animation: move 1s ease-in-out 0.5s 2 alternate;
   -moz-animation: move 1s ease-in-out 0.5s 2 alternate;
   -webkit-animation: move 1s ease-in-out 0.5s 2 alternate;
}

Keyframes

Each keyframe describes how an animated element should render at a given point in the animation sequence. The keyframes take a percentage value to specify time: 0% is the start of the animation, while 100% is the end. You can optionally add keyframes for intermediate animations.

/* Animation from 0% to 100% */

@keyframes move {
   0% { transform: translateX(0); }
   100% { transform: translateX(100px); }
} 

/* Animation with intermediate keyframes */

@keyframes move {
   0% { transform: translateX(0); }
   50% { transform: translateX(20px); }
   100% { transform: translateX(100px); }
}

The W3C has a lot of useful and detailed information on “CSS3 Animations.”

Basic Structure of Our Slider

Now that we know how transitions and animation work, let’s see how to create our slider using only CSS3. This sketch shows how the animation should work:

Sketch animation slider function
How the animation slider functions

As you can see, the slider will be a container inside of which the images will be displayed.

The animation is very simple: the image follow a predefined path, animating the top property and changing the z-index and opacity properties when the image returns to its initial position.

Let’s dive right into the HTML markup to create the slider.

2. HTML Markup

The HTML markup is very simple; it’s all organized and SEO-friendly. Let’s see the full code first and then figure out in detail how everything works.

<div class="container">
   <div id="content-slider">
      <div id="slider">  <!-- Slider container -->
         <div id="mask">  <!-- Mask -->

         <ul>
         <li id="first" class="firstanimation">  <!-- ID for tooltip and class for animation -->
         <a href="#"> <img src="images/img_1.jpg" alt="Cougar"/> </a>
         <div class="tooltip"> <h1>Cougar</h1> </div>
         </li>

         <li id="second" class="secondanimation">
         <a href="#"> <img src="images/img_2.jpg" alt="Lions"/> </a>
         <div class="tooltip"> <h1>Lions</h1> </div>
         </li>

         <li id="third" class="thirdanimation">
         <a href="#"> <img src="images/img_3.jpg" alt="Snowalker"/> </a>
         <div class="tooltip"> <h1>Snowalker</h1> </div>
         </li>

         <li id="fourth" class="fourthanimation">
         <a href="#"> <img src="images/img_4.jpg" alt="Howling"/> </a>
         <div class="tooltip"> <h1>Howling</h1> </div>
         </li>

         <li id="fifth" class="fifthanimation">
         <a href="#"> <img src="images/img_5.jpg" alt="Sunbathing"/> </a>
         <div class="tooltip"> <h1>Sunbathing</h1> </div>
         </li>
         </ul>

         </div>  <!-- End Mask -->
         <div class="progress-bar"></div>  <!-- Progress Bar -->
      </div>  <!-- End Slider Container -->
   </div>
</div>
  1. div id="slider"
    This is the main container of the slider. It does not have a particular function, but we will need it to pause the animation.
  2. div id="mask"
    We will use this to hide everything that happens outside of the slider. In addition to hiding the content, the mask allows us to display the contents of the slider.
  3. li id="first" class="firstanimation"
    Every list item has an ID and a class. The ID displays the tooltip, and the class is tied to the animation that has to occur.
  4. div class="tooltip"
    This simply displays the title of the image. You can modify it to your needs; for example, by making it clickable and adding a short description.
  5. div class="progress-bar"
    This contains the function that shows the progress of the animation.

Now it’s time for the CSS file.

3. CSS Style

Let’s create the basic structure of the slider. It will have the same image size. The border property will be useful to create a frame around the image.

/* SLIDER STRUCTURE */

#slider {
   background: #000;
   border: 5px solid #eaeaea;
   box-shadow: 1px 1px 5px rgba(0,0,0,0.7);
   height: 320px;
   width: 680px;
   margin: 40px auto 0;
   overflow: visible;
   position: relative;
}

The mask class will hide all of the elements that lie outside of the slider; its height must be equal to the height of the slider.

/* HIDE ALL OUTSIDE OF THE SLIDER */

#mask {
   overflow: hidden;
   height: 320px;
}

Finally, to sort the list of images, we’ll have position: absolute and top: -325px so that all of the images are positioned outside of the slider.

/* IMAGE LIST */

#slider ul {
   margin: 0;
   padding: 0;
   position: relative;
}

#slider li {
   width: 680px;  /* Width Image */
   height: 320px; /* Height Image */
   position: absolute;
   top: -325px;	/* Original Position - Outside of the Slider */
   list-style: none;
}

With these few lines of code, we have created our slider. Now we just need to add the animation.

4. CSS3 Keyframes Animation

Slider Animation
Image animation for the slider

Before we begin with the animation, we have to specify some parameters in order to get the right view of the animation.

As we know, the total duration of the animation will be 25 seconds, but we have to know how many keyframes equals 1 second.

So, let’s work out a series of operations that gives us the exact number of keyframes based on the images we have and the total duration of the animation. Here are the calculations:

  1. Define the total number of images to use in the slider
    5
  2. Define the length of animation for each image
    5 seconds
  3. Define the total duration of the animation
    Multiply the total number of images by the duration of each image:
    5 images × 5 seconds = 25 seconds
  4. Calculate how many keyframes equals one second
    Divide the total number of keyframes by the total duration of the animation.
    100 keyframes / 25 seconds = 4 keyframes
    4 keyframes = 1 second

With all of this math, we can now apply the CSS animation to the slider. We will be able to put the animation on infinite loop because each image will follow its own animation that activates once it comes up in the slider.

#slider li.firstanimation {
   animation: cycle 25s linear infinite;
}

#slider li.secondanimation {
   animation: cycletwo 25s linear infinite;
}

#slider li.thirdanimation {
   animation: cyclethree 25s linear infinite;
}

#slider li.fourthanimation {
   animation: cyclefour 25s linear infinite;
}

#slider li.fifthanimation {
   animation: cyclefive 25s linear infinite;
}

Once the properties of the animation have been assigned, we need to use keyframes to set the animation in motion.

Following this principle, we can connect the animations to each other even though they are separate, which will give us an infinite loop.

I’ve added the opacity and z-index properties to make the transition from one image to the next more attractive.

As you can see in the code, the first animation has more keyframes than the rest. The reason for this is that when the gallery is started, the first image is positioned to make way for the second image; but when the last image has finished its animation, the first image has to have additional keyframes in order for the user not to see a break between animation cycles.

Here is all of the code for the animations:

/* ANIMATION */

@keyframes cycle {
   0%  { top: 0px; } /* When you start the slide, the first image is already visible */
   4%  { top: 0px; } /* Original Position */
   16% { top: 0px; opacity:1; z-index:0; } /* From 4% to 16 % = for 3 seconds the image is visible */
   20% { top: 325px; opacity: 0; z-index: 0; } /* From 16% to 20% = for 1 second exit image */
   21% { top: -325px; opacity: 0; z-index: -1; } /* Return to Original Position */
   92% { top: -325px; opacity: 0; z-index: 0; }
   96% { top: -325px; opacity: 0; } /* From 96% to 100% = for 1 second enter image*/
   100%{ top: 0px; opacity: 1; }
}

@keyframes cycletwo {
   0%  { top: -325px; opacity: 0; } /* Original Position */
   16% { top: -325px; opacity: 0; }/* Starts moving after 16% to this position */
   20% { top: 0px; opacity: 1; }
   24% { top: 0px; opacity: 1; }  /* From 20% to 24% = for 1 second enter image*/
   36% { top: 0px; opacity: 1; z-index: 0; }   /* From 24% to 36 % = for 3 seconds the image is visible */
   40% { top: 325px; opacity: 0; z-index: 0; } /* From 36% to 40% = for 1 second exit image */
   41% { top: -325px; opacity: 0; z-index: -1; }   /* Return to Original Position */
   100%{ top: -325px; opacity: 0; z-index: -1; }
}

@keyframes cyclethree {
   0%  { top: -325px; opacity: 0; }
   36% { top: -325px; opacity: 0; }
   40% { top: 0px; opacity: 1; }
   44% { top: 0px; opacity: 1; }
   56% { top: 0px; opacity: 1; }
   60% { top: 325px; opacity: 0; z-index: 0; }
   61% { top: -325px; opacity: 0; z-index: -1; }
   100%{ top: -325px; opacity: 0; z-index: -1; }
}

@keyframes cyclefour {
   0%  { top: -325px; opacity: 0; }
   56% { top: -325px; opacity: 0; }
   60% { top: 0px; opacity: 1; }
   64% { top: 0px; opacity: 1; }
   76% { top: 0px; opacity: 1; z-index: 0; }
   80% { top: 325px; opacity: 0; z-index: 0; }
   81% { top: -325px; opacity: 0; z-index: -1; }
   100%{ top: -325px; opacity: 0; z-index: -1; }
}
@keyframes cyclefive {
   0%  { top: -325px; opacity: 0; }
   76% { top: -325px; opacity: 0; }
   80% { top: 0px; opacity: 1; }
   84% { top: 0px; opacity: 1; }
   96% { top: 0px; opacity: 1; z-index: 0; }
   100%{ top: 325px; opacity: 0; z-index: 0; }
}

Having created the animations, we have to add a progress bar to display the duration of each animation.

5. Progress Bar

Progress bar Animation for each image
The progress bar for each animation

The process of animating the progress bar is the same as it was for the slider. First, we create the progress bar itself:

/* PROGRESS BAR */

.progress-bar {
   position: relative;
   top: -5px;
   width: 680px;
   height: 5px;
   background: #000;
   animation: fullexpand 25s ease-out infinite;
}

Don’t be afraid of the syntax here. It has the same function as from to; you can see that the keyframes set the appearance and disappearance of each image.

/* ANIMATION BAR */

@keyframes fullexpand {
   /* In these keyframes, the progress-bar is stationary */
   0%, 20%, 40%, 60%, 80%, 100% { width: 0%; opacity: 0; }

   /* In these keyframes, the progress-bar starts to come alive */
   4%, 24%, 44%, 64%, 84% { width: 0%; opacity: 0.3; }

   /* In these keyframes, the progress-bar moves forward for 3 seconds */
   16%, 36%, 56%, 76%, 96% { width: 100%; opacity: 0.7; }

   /* In these keyframes, the progress-bar has finished his path */
   17%, 37%, 57%, 77%, 97% { width: 100%; opacity: 0.3; }

   /* In these keyframes, the progress-bar will disappear and then resume the cycle */
   18%, 38%, 58%, 78%, 98% { width: 100%; opacity: 0; }
}

6. Tooltip

The slider is more or less complete, but let’s add a few details to make it more functional. We’ll insert tooltips for the image titles that will be visible on hover.

Simple Tooltip on image
Simple tooltip

Here is the CSS for the tooltips:

   #slider .tooltip {
   background: rgba(0,0,0,0.7);
   width: 300px;
   height: 60px;
   position: relative;
   bottom: 75px;
   left: -320px;
}

#slider .tooltip h1 {
   color: #fff;
   font-size: 24px;
   font-weight: 300;
   line-height: 60px;
   padding: 0 0 0 10px;
}

Here we’ve made only the image titles visible, but you can do the same to custom text, links or whatever you like.

7. CSS3 Transitions

Tooltip Animation
Animate the tooltip on hover

We have seen how to apply CSS3 transitions to elements; now let’s do it to the tooltips.

If you remember, we added an ID to each list (first, second, etc.) to have only the tooltip associated with an image appear on hover, rather than all of the tooltips appear together.

#slider .tooltip {
…
   transition: all 0.3s ease-in-out;
}

#slider li#first: hover .tooltip,
#slider li#second: hover .tooltip,
#slider li#third: hover .tooltip,
#slider li#fourth: hover .tooltip,
#slider li#fifth: hover .tooltip {
   left: 0px;
}

8. Pause And Restart

Stop slider on mouse hover
Stop slider on mouse hover

To allow users to pause to read content or look at an image, we should stop the animation when they hover over an image. (We’ll also have to stop the animation of the progress bar.)

#slider: hover li,
#slider: hover .progress-bar {
   animation-play-state: paused;
}

9. Demo

Finally, we’ve reached the end of the tutorial. The slider is now 100% complete!

Pure CSS3 Cycle Slider
Pure CSS3 cycling slider demo

Check out the demo. It works in Firefox 5+, Safari 4+ and Google Chrome, as well as the iPhone and iPad. You can also download the ZIP file.

Thanks to Massimo Righi for his images.

10. Conclusion

The effect is impressive, but admittedly, this slider is not very versatile. For instance, to add more images, you have to edit all of keyframes. CSS3 has great potential, but it does have limits, and sometimes JavaScript is preferable, depending on your target users.

This slider has some interesting features, such as pausing on hover and uniques link for the images, which allow users to interact with the slider. If you want full support among browsers, this is not possible, so JavaScript is recommended. Unfortunately, CSS3 animation has many limitations; its lack of flexibility in particular will prevent its widespread use for now. Hopefully this will spur you on to further study of CSS3.

Feel free to share your thoughts in the comments section below!

(al) (il)


© Alessio Atzeni for Smashing Magazine, 2012.

Written by Alessio Atzeni

April 25th, 2012 at 2:10 pm

A New Front-End Methodology: BEM

without comments




  

This article is the sixth in our new series that introduces the latest, useful and freely available tools and techniques, developed and released by active members of the Web design community. The first article covered PrefixFree; the second introduced Foundation, a responsive framework; the third presented Sisyphus.js, a library for Gmail-like client-side drafts, the fourth shared with us a free plugin called GuideGuide and the fifth presented Erskine Design’s responsive grid generator Gridpak. Today, we are happy to feature a toolkit devised by Yandex: BEM.

BEM stands for “Block”, “Element”, “Modifier”. It is a front-end methodology: a new way of thinking when developing Web interfaces. This article will elaborate on the theory as well as the practice of building websites at Yandex—one of the leading internet companies in Russia.

To begin, let’s first put BEM in some historical perspective.

We first began sketching out the internal front-end framework at Yandex around the year 2007, starting with a robust CSS naming convention, and a file system layout that was associated with it. Since the naming convention was well-structured, it seemed suitable to develop certain JavaScript helpers (to work with the DOM and CSS classes in particular, on a higher level of abstraction). We then used those approaches to build an internal library of UI components that could be shared among our various websites and rich applications, built using different technology stacks (XML/XSLT, Python/Django, Perl/TT2).

As our ambitions, complexity and performance requirements grew, we aimed at replacing XSLT and Perl templates with a JS-based declarative templating DSL, built on top of Node.js. Along with those efforts, we looked into simplifying development workflow and developed a bunch of command-line tools that already helped us manage front-end code on the file system, preprocess CSS and JavaScript code, and so on, and so forth.

Some parts of the BEM stack started as open source projects, while others (like the UI component library) are being gradually open sourced. Our goal is to publish most of them during 2012.

BEM is a toolkit that will help address and resolve front-end issues quickly and effectively. It is available in a range of reusable code libraries—all of them are hosted on Github and are completely open source.

BEM Principles

One of the most common examples of a methodology in programming is Object-Oriented Programming. It’s a programming paradigm embodied by many languages. In some ways, BEM is similar to OOP—a way of describing reality in code, with a range of patterns, and a way of thinking about program entities regardless of the programming languages being used.

We’ve used BEM principles to create a set of front-end development techniques and tools that allow us to build websites quickly and maintain them over a long period of time. The principles are the following:

Unified Data Domain

Imagine an ordinary website, like the one pictured below:

ordinary website example

While developing such a website, it’s useful to mark out “blocks” from which the website consists of. For example, in this picture there are Head, Main Layout and Foot blocks. The Head in turn consists of Logo, Search, Auth Block and Menu. Main Layout contains a Page Title and a Text Block:

site marked

Giving each part of the page a name is very useful when it comes to team communication.

A project manager could ask:

  • To make the Head bigger, or
  • To create a page without a Search form in the Head.

An HTML guy could ask a fellow JavaScript developer:

  • To make Auth Block animated, etc.

Let’s now take a closer look at what constitutes BEM:

Block

A block is an independent entity, a “building block” of an application. A block can be either simple or compound (containing other blocks).

Example
Search form block:

search form block

Element

An element is a part of a block that performs a certain function. Elements are context-dependent: they only make sense in the context of the block that they belong to.

Example

An input field and a button are elements of the Search Block:

elements of search block

Means Of Describing Pages And Templates

Blocks and elements constitute page content. Besides simply being present on a page, their arrangement is also important.

Blocks (or elements) may follow each other in a certain order. For example, a list of goods on a commerce website:

list of goods on a commerce website

…or menu items:

menu items

Blocks may also be contained inside other blocks. For example, a Head Block includes other blocks:

blocks inside other blocks

Besides, our building blocks need a way to describe page layout in plain text. To do so, every block and element should have a keyword that identifies it.

A keyword designating a specific block is called Block Name. For example, Menu can be a keyword for the Menu Block and Head can be a keyword for the Head block.

A keyword designating an element is called Element Name. For example, each item in a menu is an element Item of the Menu block.

Block names must be unique within a project to unequivocally designate which block is being described. Only instances of the same block can have the same names. In this case, we can say that one block is present on the page twice (or 3, 4, times… etc.).

Element names must be unique within the scope of a block. An element can be repeated several times. For example, menu items:

repeated elements

Keywords should be put in a certain order. Any data format that supports nesting (XML, JSON) will do:

<b:page>
  <b:head>
    <b:menu>
      ...
    </b:menu>
    <e:column>
      <b:logo/>
    </e:column>
    <e:column>
      <b:search>
        <e:input/>
        <e:button>Search</e:button>
      </b:search>
    </e:column>
    <e:column>
      <b:auth>
        ...
      </b:auth>
    <e:column>
  </b:head>
</b:page>

In this example, b and e namespaces separate block nodes from element nodes.

The same in JSON:

{
  block: 'page',
  content: {
    block: 'head',
    content: [
      { block: 'menu', content: ... },
      {
        elem: 'column',
        content: { block: 'logo' }
      },
      {
        elem: 'column',
        content: [
          {
            block: 'search',
            content: [
              { elem: 'input' },
              {
                elem: 'button',
                content: 'Search'
              }
            ]
          }
        ]
      },
      {
        elem: 'column',
        content: {
          block: 'auth',
          content: ...
        }
      }
    ]
  }
}

Examples above show an object model with blocks and elements nested inside each other. This structure can also contain any number of custom data fields. We call this structure BEM Tree (by analogy with DOM tree).

Final browser markup is generated by applying template transformations (using XSL or JavaScript) to a BEM tree.

If a developer needs to move a block to a different place on a page, he does so by changing the BEM tree. Templates generate the final view themselves.

In our recent products we went with JSON as a page description format. It is then turned into HTML by a JS-based template engine. The tools we use are listed at the end of this article.

Block Independence

As projects grow, blocks tend to be added, removed, or moved around on the page. For example, you may want to swap the Logo with the Auth Block, or place the Menu under the Search Block.

swapping blocks

To make this process easier, blocks must be Independent.

An Independent block is implemented in a way that allows arbitrary placement anywhere on the page—including nesting inside another block.

Independent CSS

From the CSS point of view it means that:

  • A block (or an element) must have a unique “name” (a CSS class) that could be used in a CSS rule.
  • HTML elements must not be used in CSS selectors (.menu td) as such selectors are inherently not context-free.
  • Cascading selectors for several blocks should be avoided.
Naming for Independent CSS Classes

One of the possible naming schemes for CSS classes that satisfies said requirements is the following:

  • CSS class for a block coincides with its Block Name.
<ul class="menu">
  ...
</ul>
  • CSS class for an element is a Block Name and an Element Name separated by some character(s)
<ul class="menu">
  <li class="menu__item">
    ...
  </li>
  <li class="menu__item">
    ...
  </li>
</ul>

It’s necessary to include block name in a CSS class for an element to minimize cascading. It’s also important to use separators consistently to allow the tools and helpers to have unambiguous programmatic access to the elements.

Different naming schemes can be used. Take a look here for the naming convention we used.

Independent Templates

From the template engine’s perspective, block independence means that:

  • Blocks and elements must be described in the input data.
    Blocks (or elements) must have unique “names” to make things like “Menu should be placed here” expressible in our templates.
  • Blocks may appear anywhere in a BEM tree.
Independent templates for blocks

When coming across a block in a template, the template engine should be able to unambiguously transform it into HTML. Thus, every block should have a template for that.

For example, a template can look like this in XSL:

<xsl:template match="b:menu">
  <ul class="menu">
    <xsl:apply-templates/>
  </ul>
</xsl:template>

<xsl:template match="b:menu/e:item">
  <li class="menu__item">
    <xsl:apply-templates/>
  </li>
<xsl:template>

We are gradually discarding XSLT in our products in favor of our own JavaScript-based template engine XJST. This template engine absorbs everything we like about XSLT (we are fans of declarative programming), and implements it with JavaScript’s productivity on either the client or the server side.

We, at Yandex, write our templates using a domain-specific language called BEMHTML, which is based on XJST. The main ideas of BEMHTML are published in the BEM club on Ya.Ru (in Russian).

Blocks Reiteration

The second Menu Block can occur in the Foot Block of a website. Also, a Text Block can divide into two, separated by an advertisement.

Even if a block was developed as a singular unit, the same one can appear on a page at any moment.

In CSS related terms, this means:

  • ID-based CSS selectors must not be used.
    Only class selectors satisfy our non-uniqueness requirement.

On the JavaScript side it means:

  • Blocks with similar behavior are detected unequivocally—they have the same CSS classes.
    Using CSS class selectors allows for picking all blocks with a given name to apply the required dynamic behavior.

Modifiers For Elements And Blocks

We often need to create a block very similar to an existing one, but with a slightly altered appearance or behavior.
Let’s say, we have a task:

  • Add another Menu in the Footer with a different layout.

To avoid developing another block that is only minimally different from an existing one, we can use a Modifier.

A Modifier is a property of a block or an element that alters its look or behavior. A modifier has both a name and a value. Several modifiers can be used at once.

Example:
A block modifier specifies background color

search background

Example:
An element modifier changes the look of the “current” item

current item in menu

From the input data point of view:

  • In a BEM tree, modifiers are properties of an entity that describes a block or an element.

For example, they can be attribute nodes in XML:

<b:menu m:size="big" m:type="buttons">

  ...
</b:menu>

The same expressed in JSON:

{
  block: 'menu',
  mods: [
   { size: 'big' },
   { type: 'buttons' }
  ]
}

From the CSS point of view:

  • A modifier is an additional CSS class for a block or an element.
<ul class="menu menu_size_big menu_type_buttons">
  ...
</ul>
.menu_size_big {
  // CSS code to specify height
}
.menu_type_buttons .menu__item {
  // CSS code to change item's look
}

Element modifiers are implemented in the same fashion. Again, when writing CSS by hand, it’s very important to use separators consistently for programmatic access.

E.g., current menu item can be marked with a modifier:

<b:menu>
  <e:item>Index<e:item>
  <e:item m:state="current">Products</e:item>
  <e:item>Contact<e:item>
</b:menu>
{
  block: 'menu',
  content: [
    { elem: 'item', content: 'Index' },
    {
      elem: 'item',
      mods: { 'state' : 'current' },
      content: 'Products'
    },
    { elem: 'item', content: 'Contact' }
  ]
}
<div class="menu">
  <ul class="menu__layout">
    <li class="menu__layout-unit">
      <div class="menu__item">Index</div>
    </li>
    <li class="menu__layout-unit">
      <div class="menu__item menu__item_state_current">Products</div>
    </li>
    <li class="menu__layout-unit">
      <div class="menu__item">Contact</div>
    </li>
  </ul>
</div>
.menu__item_state_current {
  font-weight: bold;
}

Subject-Matter Abstraction

When many people work on a project, they should agree on a data domain and use it when naming their blocks and elements.

For example, a Tag Cloud block is always named Tags. Each of its elements is a Tag. This convention spreads across all languages: CSS, JavaScript, XSL, etc.

From the development process’ point of view:

  • All participants operate on the same terms.

From the CSS point of view:

  • CSS for blocks and elements can be written in a pseudo language that compiles down to CSS according to the naming convention.
  .menu {
    __layout {
      display: inline;
    }
    __layout-item {
      display: inline-block;
      ...
    }
    __item {
      _state_current {
        font-weight: bold;
      }
    }
  }

On the JavaScript side:

  • Instead of using class selectors directly to find DOM elements, a special helper library may be used.
$('menu__item').click( ... );
$('menu__item').addClass('menu__item_state_current');
$('menu').toggle('menu_size_big').toggle('menu_size_small');

The naming convention for CSS classes of blocks and elements can change over the course of time. Using special JavaScript functions to access blocks and elements (and to work with their modifiers) makes it possible to change only these functions if the naming convention changes.

Block('menu').elem('item').click( ... );
Block('menu').elem('item').setMod('state', 'current');
Block('menu').toggleMod('size', 'big', 'small');

The code above is abstract. In real life we use the JavaScript core of i-bem block from the bem-bl block library: http://bem.github.com/bem-bl/sets/common-desktop/i-bem/i-bem.ru.html (described in Russian)

Blocks Consistency

A website has a Button block with certain dynamic behavior.

When a block is hovered, it changes its appearance.

A manager could ask:

  • To use the same button on another page.

Having a CSS implementation of a block is not enough. Reusing a block also means reusing its behavior, described in JavaScript.

So a block must “know” everything about itself. To implement a block, we describe its appearance and behavior in all technologies being used—we call that Multilingualism.

Multilingual presentation is a description of a block in all the programming languages that are necessary to implement the view and the functionality of that block.

To have a block present on a page as a UI element, we need to implement it in the following techs:

  • Templates (XSL, TT2, JavaScript, etc), which turn block declarations into HTML code.
  • CSS that describes appearance of the block.

If a block has dynamic behavior, we add it to this list:

  • A JavaScript implementation for the block.

Everything that constitutes a block is a technology, including images.

File System Representation For A Block

Unequivocal Placement of Code

File Naming

When a project is:

  • Long-lived and under constant development.

If the development team:

  • Consists of several people.
  • Grows and changes.

Then being able to navigate the code base quickly is crucial.

Block code is easiest to find when it’s placed in files using the same naming scheme as the one we use for naming our entities:

menu.xsl
menu.js
menu.css
Expressing Blocks on a File System

There could be a task:

  • To reuse some blocks from a previous project for a new one.

We want the procedure of block reuse to be as simple as possible—like simply copying the files, or using partial checkout of a repository from a “donor” project. In both cases, it is useful to have all of the files under the same directory:

menu/
  menu.xsl
  menu.js
  menu.css
File Structure of a Block

When working on a project we might need to change a block at some point.

A manager could ask:

  • To change the color of the Current Menu Item, or
  • To make the Menu react on hover.

A developer could ask their colleague:

  • To help with Search Form styling for IE.

To understand where the relevant code is located, follow these (or similar) rules:

  • Block code is placed in a separate directory.
    • Directory name matches block name.
    • Implementation is placed under this directory.
  • Elements are placed in subdirectories under the block directory.
    • Directory name matches element name.
    • Implementation is placed under this directory.
  • Modifiers are placed in subdirectories under the block directory.
    • Directory name matches modifier name.
    • Implementation is placed under this directory.
    • File name includes both key and value of the modifier (again, for programmatic access).

Example
File structure of a Menu block:

menu/
  __item/
    _state/
      menu__item_state_current.css
      menu__item_state_current.xsl
    menu__item.css
    menu__item.xsl
  menu.css
  menu.js
  menu.xsl

Maintaining such file structure manually is, quite obviously, inconvenient. So we’ve developed BEM Tools to handle the burden. These tools help with creating the directory structure, placing files, generating placeholder content, etc.

Grouping Blocks in Directories

Big internet portals often need to reuse the same blocks across different websites.

There could be a task:

  • To create the same Footer on all the portals’ websites, or
  • To create a new project using blocks from the existing websites.

Working for a Web design agency often means that one has to use typical solutions for typical Web pages.

A project manager could ask you:

  • To create an order page with a Web form as on the previous project.

We have to do these tasks while preferably avoiding copying blocks around manually. So it’s nice to have a repository of shared blocks that can be linked to a project. Blocks should then be united under a single directory for that.

Such a directory is usually called Blocks.

E.g.

blocks/
  foot/
  head/
  menu/
  page/
  search/

That directory can be linked to another project straight from the version control system, so that we can make changes to shared blocks in a single location.

Levels Of Definition

If a group of blocks (united under one directory) is linked to a project directly (via a partial checkout, svn:externals, etc.), then every change committed to these blocks influences all projects.

When developing a website based on an existing one, we might want:

  • To enlarge the font in the Head on site A without affecting site B.
  • To add animation when showing a drop-down menu.

To do so, we need to be able to define or redefine blocks in different technologies for a specific website only, or for certain pages only. This can be achieved using Definition Levels.

A Definition Level is a set of blocks grouped in one directory.

An implementation of every block from the library can be changed (or completely redefined) at project level.

block levels

From page-building process’ perspective:

  • When building a page, we can set a list of levels (directories) to use their blocks on that page. E.g., build-page -l blocks-common -l blocks-my my-page.html

From the file structure point of view:

  • A project can have any number of levels. But only the levels that are evaluated during the build will be present on the page. It is possible to specify different sets of definition levels for different parts of the website.

On the JavaScript side:

  • We need to define dynamic behavior of a page in declarative style. Final behavior is gathered from different definition levels. E.g.,
/* blocks-common/dropdown/dropdown.js */
Block('dropdown', {
  init: function() {
    ...
  }
});

/* blocks-my/dropdown/dropdown.js */
Block('dropdown', {
  init: function() {
    this.__base();
    ...
  }
});

From the viewpoint of a template engine:

  • To be able to not only define, but to redefine a template, one needs to apply a preceding template implementation.
    E.g., for XSL:
<xsl:template match="b:head">
  <div> <!-- Node for extra design -->
    <xsl:apply-imports/>
  </div>
</xsl:template>

From the architectural point of view:

  • When developing a portal of several websites, we can extract a block library that serves as one of the definition levels for all the websites which are part of the portal. The blocks for a specific website will form another level.
  • The same repo can hold blocks of both desktop and mobile versions.
    Such a project will have the following levels: common, mobile, desktop. Different combinations of these levels give the resulting implementation, required by specific pages.

Open source block library bem-bl (in development) is an example of having several definition levels in one repository.

Building A Page

Working in terms of blocks means having a Subject-Matter Abstraction. This abstraction is for developers only, and browsers will get a compiled version of the code.

So we have Code For People and Code For Browsers—they are not the same.

  • Programmers code blocks—browsers get the code for the whole page.

To turn Code For People into Code For Browsers we Build a page.

Building A Page means generating HTML, CSS, and JavaScript code from a page declaration (written in XML or JSON) by applying implementations of declared blocks.

On the CSS side:

  • All CSS files are combined into a “single page” CSS file.
    Despite the fact that CSS for every block, element or modifier is stored in separate files, we don’t have to link these files to the page as is. It’s possible to collect all the required CSS implementations into one file.
    This also solves the well-known “number of imports” issue in IE, and decreases the number of HTTP requests. For combining CSS we use borschik.
  • Browser gets minimized code.
    When building CSS, we can minimize and optimize CSS code using the CSSO utility, for example.
  • Each browser can get CSS code written especially for it.
    It is also possible to divide CSS implementations for different browsers and deliver only the code needed for each browser.
    setochka—currently in prototype can be used for that.

From the JavaScript point of view:

  • Similarly to CSS, JavaScript files can be combined into one.

From the template engine’s point of view:

  • Only needed templates are included.
    Final set of templates that are used for displaying a page includes only the templates for required blocks. This boosts template performance and reduces the likelihood of side effects.

From the viewpoint of development process:

  • Robots serve people (not the other way around).
    Developer writes code as they see fit. “Robots” take (some) care of performance by optimizing the code (together with making it unreadable) when building a page.

In terms of work organization:

  • Division of labor.
    We have developers working on the core framework (compilers, tools, performance); library developers, who maintain the block library; application developers, who develop websites using the framework.

We use BEM tools to build pages.

How to Automate the Building Process?

The usage of bem tools requires to run several commands for each page whenever page input data or blocks implementation are changed. As a result of these commands, you get CSS and JavaScript files for the page, page’s template, and if you are developing static pages, the HTML code of your page.

To avoid running these commands manually, there is also the GNUmakefile, which was written for a project that includes the instructions on how to build pages.
You can find an example of such a file in the test project bem-bl-test.

But the usage of GNU Make has a list of problems:

  • You have to run it every time you have changed something.
  • Every time you run gmake, it reads the information from a disk. So the compilation process could not be fast.
  • The pages you build not only depend on the content of block files, but on their file structure as well. But it’s impossible to write a gmake goal dependency in these terms.

So we’d like to create something to replace GNU Make for the process of page building. This will be both a development server and a tool to build production files. Bem Server will be run in a project root directory, and give HTTP response with the page files built (so you won’t need to run gmake manually after each change).
Besides, it will be able to watch the files (the adding and removing of them) via fs.FSWatcher that help to chache results efficiently.

BEM Server is a subcommand of bem-tools. Currently it can run an HTTP server, apply BEMhtml templates to BEMjson data and inline CSS imports using borschik utility.

Real Examples

Yandex is a large (mostly Russian) company that use BEM methodology to develop its services.

BEM methodology does not request that you use a certain framework. You also don’t have to use BEM for all the technologies you have on your pages (but that would be the most efficient).

All the services of Yandex have BEM in their CSS and JavaScript code and XSL templates for their pages. E.g.,

Some services don’t use XSL templates, building their pages with our newest template product, Bemhtml template engine which was mentioned above. These are the following services:

There are also other companies that use BEM methodology.

For example, the guys at Mail.ru partly use BEM for their services. Some blocks on their pages are BEM-based in terms of CSS code. They also have their own C++ template engine, and write block templates according to this methodology.

More examples:

You also may be interested in websites that use bem-bl block library (in development):

Libraries

Tools

Additional Information

(jvb)


© Varvara Stepanova for Smashing Magazine, 2012.

Explore Coverage LIVE From Nashville

without comments

Get live event coverage from thought leading presenters at Nashville, Friday, 4/13 beginning at 8:00 a.m. CST.




The Lowdown on Structured Data and Schema.org – Your Questions Answered!

without comments

Posted by Daniel Butler

First of all, thank you to everyone who listened in to the Microformats and Schema.org webinar with Richard Baxter and myself. If you are a PRO member and haven't had a chance to listen in, be sure to check it out!

During and after the webinar we received a ton of great feedback and questions which we unfortunately just didn't have time to cover off (ah man!). But…as they were awesome questions, SEOmoz have given us the chance to rock out a blog post as a follow up. So, sit back and enjoy as we take your head from confusion to conclusion.

1. Can you show/speak about pros and cons of using Schema versus using micro formats?

I don't think we can really compare micro formats to schema.org directly – micro formats are a form of structured data, like microdata and RDFa with a limited set of pre-defined properties. The sole purpose of Schema.org is to extend the vocabulary used in structured data, and at the moment only microdata can be combined with Schema.org. Although there has been talk of plans to start using RDFa.

Due to the extensive vocabulary on offer and universal support from the major search engines, the future is looking bright for the growth of Schema.org. Can the same really be said for micro-formats? IMO no, it's an easy to understand mark up but doesn't have the universal support to maintain growth.

2. What are other advantages of using schema and microdata except for getting better rich snippets?

Marking up items on a web page creates a stronger overall definition of what the content is really about. Aaron Bradley wrote a great blog post on seoskeptic.com deciphering Google's semantic search intentions.

You only need to look at Google's recipe search as an example of what is starting to evolve from the data contained within the mark up we install.

3. Did you guys notice any improvement in rankings after implementing schema?

I personally haven't seen a direct impact on rankings from integrating any form of structured data, but that doesn't mean it won't happen in the near future. With the purchase of Metaweb/Freebase back in 2010, and new developments for its Semantic search on the horizon, we can only guess this will be playing a greater role.

4. What are some practical applications of micro data or micro formats with a higher education institute? Is it possible to define a new "item type" such as courses, degrees, etc?

Ok, let's break down a few ideas which have the potential to generate a rich snippet for an Educational institute, first up ‘Place'.

There is a schema type for Educational Organization that allows us to mark up the name and location of the institute, resulting in the address featuring in the rich snippet. The mark up would resemble something like:

<div itemscope itemtype="http://schema.org/EducationalOrganization">
<span itemprop="name"></span>
<div itemprop="address" itemscope itemtype="schema.org/PostalAddress">
<span itemprop="streetAddress"></span>
<span itemprop="addressLocality"></span>
<span itemprop="addressRegion"></span> <span itemprop="postalCode"></span> </div>

With regards to the courses themselves, why not gather some reviews from recent graduates for each course. This can then be marked up with standard Review schema, but then combined with some additional mark up to describe the actual person who left the review as a recent graduate. This can be done using the itemprop="alumni":

<span itemprop="alumni" itemscope itemtype="http://schema.org/Person">
<span itemprop="name"></span>

So now that we have a few reviews and ratings from recent graduates, why not take this one step further and create an aggregate rating with schema.org, which will ultimately lead to the star rating rich snippet.

If the resource is available another awesome addition to a course page would be a very quick introductory video of each course. This in turn can be marked up using schema's VideoObject, which when combined with video XML sitemaps, correct video formatting and a bunch of other items described in this cool post by Geoff of Distilled, will lead to a video thumbnail being generated in the search results. Here is a quick piece of Schema video mark up:

<div itemprop="video" itemscope itemtype="http://schema.org/VideoObject"> <span itemprop="name">[feature the exact title of the video]</span> <meta itemprop="duration" content="[duration of the video in the format: T0M53S]" /> <meta itemprop="thumbnail" content="[video thumbnail url]" /> <meta itemprop="uploadDate" content="[the upload date and time of video in ISO format e.g. 2012-03-14T09:00:00+09:00]"> <span itemprop="description"></span>

Here are a few other things which could result in a rich snippet for an educational institute:

  • Selling books/resources for use with each course online? – This content could be marked up using a combination of Book and Product schema.
  • Are you running open days/workshops for related courses? – Perfect opportunity to use the EducationEvent schema.

As for defining new ‘item types' it is totally possible, check out the extension mechanism. This will allow applications to develop a basic level of understanding of the mark up used, but it's unlikely to lead to a rich snippet being generated unless there is a large/growing popularity for the particular item type.

However the Schema vocabulary is growing, so although there may not be a defining type right now there could well be in the near future. For example there has been recent talk of collaboration between ESPN and Google to define a new Sports schema.

5. With the review section… wouldn't this allow websites to manipulate their ratings? How will this be monitored by Google?

Yes, and it's been happening, A LOT! Originally there was an approval process for a domain to become white-listed for rich snippets, which involved informing Google via a simple form submission. But I remember it having a pretty heavy waiting list, anything from 4 weeks to 6 months.

This eventually changed, and the approval speed for websites significantly improved (relying primarily on algorithmic validation). Within a day or so of implementing a set of mark up, rich snippets were being generated. This of course then led to a lot of the abuse, and a crackdown on spam by Google allowing people to report rich snippet spam.

There are always going to be questions on the validity of review data, but it's a really tricky one to judge. I wonder whether trusted third party review platforms could play a greater role in helping to filter out spam in a similar way to that seen in Google Shopping, but even then they are still open to abuse.

6. In the IMdb example the image has an item property on it but it is not in the search result. Why is this?

Very good question, this would make for such an awesome rich snippet. Outside of video thumbnails, software applications, recipe search, and news/articles, rich snippet support for the image property is still quite restricted.

7. Do you have an example of breadcrumbs showing up in results?

Motorauthority.com uses microdata to mark up its breadcrumb trail, resulting in the following snippet:

8. Do you know of any way to mark up a "product category" page? Not a product aggregator page (a list of the same products available from different vendors), but, say, an e-commerce category page that lists different products?

Ok, let's say we are a kick ass clothing store and stock merchandise from a number of cool brands like Animal, Quicksilver, Rip Curl etc. Let's take a broad category like ‘Animal' as our example, which includes products like bags, shirts, shorts and hoodies – there are a couple of things we could affectively do:

  1. Aggregate review data across all Animal products to create an overall rating (– or ‘popularity' score if you like) for the brand category.
  2. Aggregate the price of all products in the category using schema.org/AggregateOffer – marking up the total number of products available in the category, and the min and max price of associated products to add the price range to the rich snippet.

The code for this would resemble something like:

<div itemscope itemtype="http://schema.org/Product"> <span itemprop="name"><span itemprop="brand">Animal</span></span> <div itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating"> Products in the Animal category have been rated <span itemprop="ratingValue">5</span> out of <span itemprop="bestRating">5</span> based on <span itemprop="ratingCount">387</span> reviews. </div> <div itemprop="offers" itemscope itemtype="http://schema.org/AggregateOffer"> There are <span itemprop="offerCount">120</span> clothing products on sale, ranging from <span itemprop="lowPrice">$10.00</span> to <span itemprop="highPrice">$120.00</span> </div>

Using the above code, here is an example rich snippet:

9. Does associating CSS with these microformat classes have any negative effect?

Applying CSS formatting directly to any of the properties of the mark up language shouldn't affect the rich snippet code in any way. As long as the correct naming conventions have been used, there shouldn't be any trouble.

10. Is there a Rich Snippet Generator and Schema Generator you would recommend?

There aren't a huge amount of actual code generators, but here are the ones I'm aware of:

Here's a list of some other tools and plug-ins which may also be of use.

11. Does it matter where you put any of these markup codes on the site?

The actual location of the mark up on a web page doesn't impact the ability to generate rich snippets. The ordering of mark up can however, especially when nesting elements, so be sure to test thoroughly using the Google testing tool, or the Bing WMT equivalent.

Thanks again to all those who submitted questions. We hope that this post provides the answers you were seeking, and if there are any new questions please fire away in the comments!

Sign up for The Moz Top 10, a semimonthly mailer updating you on the top ten hottest pieces of SEO news, tips, and rad links uncovered by the Moz team. Think of it as your exclusive digest of stuff you don’t have time to hunt down but want to read!

Written by Daniel Butler

March 27th, 2012 at 9:10 pm

How Garbage Ranks in the SERPs: a Case Study

without comments

Posted by Eppie Vojt

You've built a fantastic site full of excellent, link-worthy content.  You're actively building relationships in the social space that send quality traffic to your site and establish your authority within your industry.  You've focused on creating a great user experience and deliver value to your site's visitors… and yet you're still getting outranked by garbage websites that objectively don't deserve to show up ahead of you.

In short, you're following the advice that all the top SEO experts are giving out, but you simply can't pull the same quantity of links that some of your less ethical competition is nabbing.  Maybe we can learn a thing or two from that trash that's pushing you down in the SERPs and start copying their links.

How Does Garbage Rank?

A Prime Example of Garbage in the SERPs

To determine how low value sites are able to rank for competitive terms, we're going to dissect one of the most astonishing achievements in SERP manipulation I've seen in a long time — a situation where several billion dollar brands got stomped by a low quality site for some of the most competitive (and valuable) terms online.  "Car Insurance" and "auto insurance" (and a host of related terms).

Take a look at these search results and I'm sure you can spot the outlier (hint… I put a box around it, wrote something next to it, and drew a big red arrow pointing to it):

Car Insurance Search Result

You found it? Awesomesauce! There, sitting pretty at #2 for one of the Holy Grail search terms, right in between Progressive and Geico was… AutoInsuranceQuotesEasy.com?  Not the most trustworthy looking domain name but to rank second for car insurance (and fourth for "auto insurance") it must be an impressive site, right?

Surely it's going to be stuffed with linkbait content like lists of the least and most expensive cars to insure, lists of the most expensive cities and states to insure a vehicle, calculators for determining the right amount of insurance to get, tips for lowering your insurance rate, and lists of the most frequently stolen or vandalized cars.  It'll be very attractive and super user friendly.  Has to be, doesn't it?

A Look at the Site

AutoInsuranceQuotesEasy.com

Far from it — it's a large lead capture form at the top of the page (powered by Sure Hits), some low quality text content below it, and a single navigation item (leading to the site's blog).  Nothing else.

The site's blog doesn't prove to be a whole lot better, as it's jam packed with poorly written content, most of which exists only to create a reasonable amount of space in between repetitions of keyword phrases.

When I find a site like this ranking in a competitive niche, my first thought is always that the search result I'm seeing might be an anomaly.  I double-checked with my buddy Ian Howells (@ianhowells - smart dude) and he was seeing the same thing.  Then I looked it up at SEMrush.com, where I saw this:

SEM Rush data for autoinsurancequoteseasy.com
 

Looks Like Google Forgot to Take Out the Trash

This was no fluke.  In under a year this site had gone from a newly registered domain (December 2010 registration date) to the top of the mountain of search, ranking for some of the most competitive terms online.  SEM Rush estimated the paid search equivalent value of the traffic received by this domain to be over $4 million… per month!

That's a lot of scratch generated by a site that's not employing a single one of the methods most leading SEO experts currently preach… so what gives?

Well, to find out, let's head on over to Open Site Explorer and Majestic SEO to take a closer look at how a simple lead capture site was able to build up enough authority to outrank the world's most famous insurance-touting lizard… and what we can learn from it to help our sites climb the search rankings.

Link Microscope

From Majestic SEO, I was able to pull a backlinks discovery chart that shows approximate numbers for the amount of new links added per month.  It's pretty clear that these guys weren't messing around with a conservative link velocity.  They really got after it, adding a considerable amount of new links early in the site's life cycle and became even more aggressive starting in October.  This second push correlates pretty nicely with the spike in organic search traffic shown above from SEMrush.

Majestic SEO Backlink Discovery Chart

So we know that this site grabbed top rankings for some super competitive keywords and held the position for several months.  We also know it employed an aggressive link building campaign.  It's time to dive deeper into what these links looked like and where they were placed to see if we can replicate them.

After running an export of AutoInsuranceQuotesEasy.com's link profile from OSE, I started to analyze their link profile, focusing initially on anchor text distribution.  Looking at the chart below, you'll notice that the site is very heavily weighted towards targeted anchor text.  Their top 10 most frequently occurring anchor texts made up nearly 80% of all links.

anchor text distribution chart

 

Within the subset of links that contain targeted anchor text, there's a fair amount of variety, though the vast majority of the links contain some modified form of "auto insurance" and "car insurance."  All interesting information, but before looking at this chart, we all probably knew that the site was going to be ranking based on heavy usage of anchor text.  That isn't super actionable data — if we were looking to compete in this space, we'd already plan on trying to get lots of exact and partial match links.

But what if there was an easy way to burn through this list of links and spot the ones that would be super easy to copy?  What if, without having to manually load a single page, we could identify all of the blog comments, blogroll links, author bios, footer links, resource boxes, link lists, and private blog network posts?  Wouldn't that be helpful?  Even for the ultra-white hats, using this approach could eliminate these cheap links and make it more efficient to identify legitimate editorial links that you might try to match.

Taking Link Analysis a Step Further — Using Semantic Markup to Identify Link Types

The good news is that we can quickly sift through a mountain of backlinks and reliably segment them into groups.  Thanks to the adoption of semantic markup over the past few years, most websites happily give this information away.

"What's semantic markup?" some of you ask.  It's code that inherently has meaning.  Code that describes its own purpose to the browser (or crawler).  In a perfect world, that means elements like <header>, <article>, and <footer>.  Those are all available in HTML 5.  But since the advent of id and class names in markup, developers have been trying to add meaning to what would otherwise be ambiguous code.  Most of the web is now built to look like this:

<div class="comment">My comment goes here</div>

or this:

<div id="footer">Copyright info, etc.</div>

Sadly, it doesn't quite look like this:

<a href="my-spammy-website" class="spam-links">My spammy anchor text</a>

But there's enough meaning built in to most id and class names that we can start to discern quite quickly what most elements mean.  Knowing that this is a pretty standard convention, it's not too hard to build a crawler that will analyze this data for us, looping through each line of our OSE export.  For each entry it will (this is going to get a little nerdy, so bear with me):

  1. Fetch the url of the page that contains the link to the target site
  2. Convert that info into a Document Object Model (DOM) object
  3. Run an xPath query to find the link on the page with a matching href value
  4. Reverse traverse the DOM, looking for containing elements that contain a class or id value that matches a link-type pattern

In non-geek speak, that means that we check to see if our link sits inside of a container that has a recognizable id or class name.

Classifying the Links

If, during that reverse traversal, it finds a match, we can effectively label that link.  So if our link appears inside a div with the id of "footer" we can label that as a footer link.  If it's in a div or paragraph (or any other element) with the class of "comment-37268," we can still call it a match and note that it's a comment link.

We can add a second level of information on comment links by searching the DOM for all external links on the page and counting the total.  The higher the number, the greater the likelihood that the site is auto-approving comments.

If we fail to retrieve the page or we get the page but the link is no longer present, we can label the link as dead.

We can also do some simple domain matching on known article directories, web directories, and web 2.0 properties, though for this example I only used a few domains for each of these groupings.  With larger lists, the "unknown" link types would likely shrink.

With the crawler built and running, I was able to pull the following data for this site (dead links removed):

Link type distribution

 

Gaining control of other sites

The chart above starts to paint a much clearer picture of how these rankings were built — blog commenting, article marketing, and sidebar links played a big role in boosting this site's link profile.

What do those links have in common?  They are very unlikely to be legitimate editorial links.  Instead, it looks like the rankings for this site were built on "link dropping," the process of leveraging control of an independent site to leave your own link without oversight or review.

Since we've been able to automatically identify roughly 65% of the live links to the site, we've got a smaller unknown group to work with now. as a result, we can pull some of those remaining unidentified links for manual review.  And that's where we see gems like this:

Not exactly contextual links

Sifting through a sampling of these unclassified links, we see a bunch of web sites like this, which to a machine look like contextual links in the main content area.  Obviously, this doesn't stand up to human review and is a completely indefensible link building strategy.

We also spot a bunch of links on sites with posts covering a wide range of topics.  They're publishing new content pretty frequently and every post has links in it with targeted anchor text (to highly profitable niches).

These types of posts come from one of the most effective link dropping strategies working today — the use of private blog networks.  So let's start to look into how we can more accurately classify these links by network so we can start posting to them as well.

The Next Step: Domain Matching to Identify Private Blog Networks

Effective private blog networks are built to have no footprint.  They look like completely independent sites, don't interlink, and have no shared code.  When done correctly, they won't share an IP address, Google AdSense publisher ID, or Google Analytics account.  In short, they can't be spotted by analyzing the on-page content.

A truly private blog network (one owned entirely by a company that uses it to get their own rankings), is almost impossible to identify.  Blog networks that are open to paid membership (like Build My Rank, Authority Link Network, Linkvana, and High PR Society) are easier to spot — though not without cost.

The way we can pick out the domains in these networks is to create content with a shared unique phrase (or link to a decoy domain). Once this content is published and indexed, we can scrape Google for listings containing the target phrase.  Once we have the list of URLs where our content has been published, we can cull out the domain names and add them to a match list.

With links classified into groups, we can now export lists that all have the same tactical approach to duplication.  That makes it super easy to outsource this stuff.  Send the list of blog comments to someone (or a team of people) and have them start matching links.  If you're particularly daring, you can completely automate this using Scrapebox — it all depends on your personal ethics and risk tolerance.

Same thing with web directories — these are links that can be acquired with brute force, so commit lower cost resources into acquiring them.

Sidebar, footer, and blogroll links are most likely paid links, part of a private blog network (hopefully we've matched the domains and reclassified those), or possibly valid resource lists.  Contacting webmasters to find out what it takes to get a link in those areas requires a little more finesse, but with a little guidance, junior team members can handle these tasks.

If they match our private blog network list, we can submit posts through on those networks.

A Word of Caution

Be careful who you copy.  The site I referenced in this article has already been dropped by Google (I wouldn't have published this if they were still ranking).  I suspect it was a manual action, since the site had a pretty stable three months at the top (even in the age of Panda).  Google just can't allow low quality sites to outrank billion dollar brands for high visibility terms, and I believe they took corrective action to create a better user experience for the search terms this site ranked for.

It's possible that they didn't just implement this on a domain level, but instead stripped the sites that linked to AutoInsuranceQuotesEasy.com of their ability pass juice.  That would mean that if you were duplicating this site's links, you'd be out of business too.  Always weigh the risk against the reward and NEVER gamble with a client's site without getting approval (in writing) from them that they are comfortable with the risk of losing all of their rankings.

Want to Analyze Links for Yourself? I've Got You Covered

Obviously, since I have the data for the site used in this case study, I've actually built the tool talked about in the "Using Semantic Markup…" section of this post.  For my purposes, it didn't need a fancy design or multiple user management, and I ALMOST published this post without bothering to put that stuff together.  Thankfully, some of my friends in the SEO community (Ethan Lyon, Mike King, Dan Shure, Nick Eubanks, Ian Howells) pushed for me to make this application usable by other people, so…

You can start analyzing links using Link Detective for your own projects today.

If you want to know when new features get rolled in to the application, just follow me at @eppievojt on Twitter.  I'll also make note of it on my (infrequently updated) personal website, eppie.net.

Sign up for The Moz Top 10, a semimonthly mailer updating you on the top ten hottest pieces of SEO news, tips, and rad links uncovered by the Moz team. Think of it as your exclusive digest of stuff you don’t have time to hunt down but want to read!

Written by Eppie Vojt

March 15th, 2012 at 11:58 am

Introduction To Linux Commands

without comments




  

At the heart of every modern Mac and Linux computer is the “terminal.” The terminal evolved from the text-based computer terminals of the 1960s and ’70s, which themselves replaced punch cards as the main way to interact with a computer. It’s also known as the command shell, or simply “shell.” Windows has one, too, but it’s called the “command prompt” and is descended from the MS-DOS of the 1980s.

Mac, Linux and Windows computers today are mainly controlled through user-friendly feature-rich graphical user interfaces (GUIs), with menus, scroll bars and drag-and-drop interfaces. But all of the basic stuff can still be accomplished by typing text commands into the terminal or command prompt.

Using Finder or Explorer to open a folder is akin to the cd command (for “change directory”). Viewing the contents of a folder is like ls (short for “list,” or dir in Microsoft’s command prompt). And there are hundreds more for moving files, editing files, launching applications, manipulating images, backing up and restoring stuff, and much more.

So, why would anyone want to bother with these text commands when you can use the mouse instead? The main reason is that they are very useful for controlling remote computers on which a GUI is not available, particularly Web servers, and especially Linux Web servers that have been stripped of all unnecessary graphical software.

Sometimes these lean Linux servers are managed through a Web browser interface, such as cPanel or Plesk, letting you create databases, email addresses and websites; but sometimes that is not enough. This article provides a broad introduction to text commands and the situations in which they are useful. We’ll cover the following:

  • Why knowing a few commands is useful;
  • Issuing commands on your own computer;
  • Using SSH to log into your Web server;
  • Getting your bearings: pwd, cs ls;
  • Viewing and moving files: cat, more, head, tail, mv, cp, rm;
  • Searching for files: find;
  • Looking through and editing files: grep, vi;
  • Backing up and restoring files and databases: tar, zip, unzip, mysqldump, mysql;
  • File permissions: chmod.

Why Knowing A Few Linux Commands Is Useful

As a website developer or server administrator, you would gain a big asset in becoming comfortable with these commands: for website emergencies, to configure a server and for your CV. It can also save you money. Many hosting companies offer fully managed servers but at a high monthly premium. Or else they charge by the hour for technical support.

Perhaps you need to archive some big files or make a change to the httpd.conf file or figure out why your website’s images have suddenly stopped loading. You might not want to pay $50 to your server’s administrator for a five-minute job. This article gives you the tools to make such changes yourself.

And why “Linux” commands? Two main types of servers are available today: Windows and UNIX. UNIX-based servers include Linux (which split off in 1991), Mac OS X (2002) and several more traditional UNIX systems, such as BSD, Solaris and HP-UX. Linux commands are basically UNIX commands and so will run on all of them. In fact, I use the term “Linux” here only because it is more common and less frightening than “UNIX.” Windows servers, on the other hand, have a much smaller market share and are more often controlled through GUIs, such as Remote Desktop and VNC, rather than the command line.

In fact, a November 2011 survey showed that Apache accounted for about 65% of all Web servers. Apache usually runs in the popular LAMP configuration: Linux, Apache, MySQL and PHP. Microsoft was a distant second, with 15%. Third place nginx runs on Linux, UNIX, Mac and Windows. So, the commands in this article will work on at least two thirds of all servers.

Issuing Commands To Your Own Computer

You can quickly experiment with text commands on your own computer. On Mac with OS X, go to Applications ? Utilities, and run Terminal. On a PC with Windows, go to Start ? All Programs ? Accessories, and choose “Command Prompt.” On Ubuntu Linux, go to Applications ? Accessories, and choose Terminal.

On Windows you should see this:

The Windows command prompt

This is the command line (i.e. shell, prompt or terminal) on your own computer. You can type dir on Windows or ls on Linux or Mac followed by “Enter” to see a list of the files in the current “directory” (i.e. folder, location or path).

All we will be doing for the rest of this article is opening up one of these terminals on a remote computer: your Web server.

You may have used VNC or Remote Desktop, which allow you to actually view the desktop on someone else’s computer: your screen shows their screen, your mouse controls their mouse, your keyboard mimics their keyboard.

The terminal is similar to this but without the fancy menus or scroll bars. If you were to plug a keyboard and screen into your Web server, sitting in a fireproof basement somewhere, you would probably see one of these terminals, waiting patiently for your user name and password.

Using SSH To Log Into Your Web Server

The application SSH, or Secure Shell, is used to log into Web servers. It often takes the same user name and password as FTP, but it has to be allowed by your host. If you have a dedicated Web server, it is probably already allowed. If you use cloud hosting, then you might need to request it first. If you are on shared hosting, you’ll definitely need to request it, and the administrator may refuse.

On Linux or Mac, open up Terminal as described above and type the following:

ssh -l username www.myserver.com

The -l stands for “log in as,” and your user name goes after it. If SSH is allowed, then it will ask for a password. If not, you’ll get an error message, like this one:

SSH Command and Connection Error

Running the ssh command and being denied access

On Windows, you will need to download some SSH software. Putty is a popular and easy choice. It downloads as a single EXE file, which you can save to your desktop and run right away. Type your website as the host name, check the SSH box under “Connection Type,” and click “Open.” It will ask for your user name and then your password.

Running Putty on Windows

Running Putty on Windows in order to SSH to your Web server

Once successfully logged in, you will usually see a welcome message. After that, you will be presented with a few letters and a $ sign (or a # sign if you have logged in as root). The letters often represent your user name and where you’ve come from, or the name of the server. A ~ indicates that you are in your home directory. The $ is the prompt; it indicates that you can start typing commands now, something like:

Successful SSH to a server

A successful SSH log-in to a Web server. The $ means we can start typing commands.

The next section introduces a few basic commands.

Getting Your Bearings

On Windows, when you go to “My Documents” from the Start menu, it opens your “My Documents” directory in Windows Explorer and shows the contents. If some nosy colleague walked by and asked “What directory are you in?” you could say “I’m in my documents.”

If you SSH’ed to a server as the user “admin,” you would land in admin’s home directory, probably /home/admin. You can verify this by typing the command pwd, which shows your current location (i.e. folder, directory or path).

The pwd and ls commands

The pwd command tells you where you are, cd changes the directory and ls shows the contents of a directory.

To change to another directory, use the cd command with the destination, like so:

cd /

This will change the directory to /, the top of the whole UNIX directory structure. The command ls lists the contents of the current directory, in this case /.

In the screenshot above, the terminal is color-coded. Dark-blue entries are subdirectories, and black entries are files. A lot of the interesting stuff on Web servers happens in the /etc, /home and /var directories. Using just cd and ls, you can explore your server and find out where stuff is.

When using cd, you can specify the new directory absolutely (beginning with a slash, like /var/www) or relative to your current location (without the initial slash). You can also go up a directory with two dots. Practice with the sequence below, pressing “Enter” after each command. Can you guess what the last command will tell you?

cd /var
ls
cd www
ls
cd ..
pwd

Viewing And Moving Files

On many Linux servers, websites are located in /var/www/vhosts. You can check on your server by doing the following:

cd /var/www/vhosts
ls

If you see a list of websites, you can move into one of them. Within the website’s main directory, you will probably see the same files that you see when you FTP to the website, things such as httpdocs (where your website’s files are), httpsdocs (if you have a separate secure website), conf (configuration files), statistics (logs and compiled statistics), error_docs, private and more.

You can then change into your website’s public-facing directory, which is myserver.com/httpdocs in this example:

cd myserver.com
ls
cd httpdocs
ls

Now you have arrived, and you can run a new command, cat, which displays the contents of a file. For instance, if you have an index.html file, run:

cat index.html

If your index.html file is more than a few lines long, it will rush past in a blur. You can use the more command to show it slowly, one page at time. After you type the command below, it will show you the first page. You can press the space bar to show the next page, “Enter” to show the next line, and Q to quit.

more index.html

You can also show just the first few or last few lines of a file with the head and tail commands. It shows 10 lines by default, but you can pass in any number:

head index.html
tail -20 index.html

If you would like to rename this file, use the mv command, short for “move”:

mv index.html indexold.html

Similarly, the cp is the copy command, and rm removes files.

cp index.html indexold.html
rm indexold.html

Below is a string of commands in action. In order, it confirms the current directory with pwd, looks at the contents with ls, views index.html with cat, then renames it with mv, and finally removes it with rm, with a lot of ls in between to show the changes.

The cat and mv commands

The cat, mv and rm commands in action, for displaying, moving and then removing a file.

More Advanced Tip: Changing the Prompt

Note that in our initial examples, the full prompt included the current directory. For instance, in [admin@myserver /]$, the / indicated that the user was in the / directory. In the example directly above, it was removed, or else it would have crowded the screenshot by constantly saying [admin@myserver /var/www/vhosts/myserver.com/httpdocs]$.

You can change the prompt to whatever you want by setting the PS1 environment variable. Here are a couple of examples, the latter including the user, host and current directory:

PS1="[woohoooo ]$ "
PS1='[${USER}@${HOSTNAME} ${PWD}]$ '

Searching For Files

On big websites, files can get lost. Perhaps you vaguely remember uploading a new version of your client’s logo about four months ago, but it has since fallen out of favor and been replaced. Now, out of the blue, the client wants it back. You could download everything from the server using FTP and search the files using Finder or Explorer. Or you could log in and search using the command line.

The find command can search through files by name, size and modified time. If you just give it a directory, it will list everything that the directory contains. Try this:

find /var/www

You will probably see lots and lots of file names whizzing past. If you have many websites, it could continue for a couple of minutes. You can stop it by hitting Control + C (i.e. holding down the Control key on your keyboard and pressing the letter C). That’s the way to interrupt a Linux command. A more useful command would be:

find /var/www | more

The pipe symbol (|) takes the output of one command (in this case, the long list of files produced by find) and passes it to another command (in this case, more, which shows you one page of files at a time). As above, press the space bar to show the next page, and Q to quit.

To search for a specific file name, add -name and the file name. You can use \* as a wild card (the backslash is not always necessary but is good practice with the find command). You can combine searches using -o (for “or”). If you leave out the -o, it becomes an “and.”

find /var/www -name logo.gif
find /var/www -name \*.gif
find /var/www -name \*.gif -o -name \*.jpg

You can also search by size by adding -size. So, you could look for all GIFs between 5 and 10 KB:

find /var/www -name \*.gif -size +5k -size -10k

Similarly, to find a file that was last changed between 90 and 180 days ago, you can use -ctime:

find /var/www -name \*.gif -ctime +90 -ctime -180

In both of these cases, you will probably also want to know the actual file size and date last changed. For this, you can add -printf, which is similar to the C function printf in that you use the % sign to output various information. This command outputs the file size (up to 15 characters wide), the date and time changed (down to the nanosecond) and the file name:

find /var/www -name \*.gif -size +5k -size -10k -ctime +90 -ctime -180 -printf "%10s  %c  %p\n"

With that whopper, you have hopefully found the missing file. Here is an example:

Variations on the find command

Searching for all GIFs within a single website, and displaying the file sizes, changed times and file names.

Another useful parameter is -cmin, which lets you see files that have changed in the last few minutes. So, if something goes wrong on a website, you can run this to see everything that has changed in the last 10 minutes:

find /var/www -cmin -10 -printf "%c %p\n"

This will show files and directories that have changed. Thus, it won’t show files that have been removed (because they are no longer there), but it will show the directories that they were removed from. To show only files, add -type f:

find /var/www -cmin -10 -type f -printf "%c %p\n"

More Advanced Tip: Reading the Manual

I didn’t have to remember all of the variations above. I consulted the manual several times, like so:

man find

While reading a manual page, the controls are the same as more: space bar for paging, “Enter” to go forward one line and Q to quit. The up and down arrows also work. You can search within a page of the manual by typing / and a keyword, such as /printf. This will jump you to the next occurrence of that term. You can search backwards with ?printf, and you can repeat the search by pressing N.

Looking Through And Editing Files

Most visual code editors allow you to search through many files when you’re looking for a particular variable or bit of HTML. You can also do this directly on the server using the command grep. This is useful when something goes wrong on a complex website with hundreds of files and you have to find the error and fix it fast.

Let’s say you view the HTML source and see that the error happens right after <div id="left">. You can let grep do the searching for you. Give it the thing to be searched for and the files to search in. These commands change to the website directory and grep through all files ending in php. You need to put quotes around the HTML because it contains spaces, and the inner quotes have to be escaped with backslashes:

cd /var/www/vhosts/myserver.com/httpdocs/
grep "<div id=\"left\">" *.php

This will tell you which files in the current directory contain that bit of HTML. If you want to search in subdirectories, you can use the -r option with a directory at the end, instead of a list of files. The single dot tells it to start in the current directory.

grep -r "<div id=\"left\">" .

Alternatively, you could use the find command from above to tell it which files to look in. To put a command within a command, enclose it in back apostrophes. The following searches only for the HTML in PHP files modified in the last 14 days:

grep "<div id=\"left\">" `find . -name \*.php -ctime -14`

You can also add -n to show the line numbers, as in this example:

Using grep to look for things inside files

Searching for a bit of HTML within the PHP files in the current directory

And how do you quickly fix an error when you find it? To do that, you will need to start up a Linux text editor. Different editors are available, such as pico and emacs, but the one that is guaranteed to be there is vi. To edit a file, type vi and the file name:

vi index.php

vi is a complex editor. It can do most of the amazing things that a fully featured visual editor can do, but without the mouse. In brief, you can use the arrow keys to get around the file (or H, J, K and L on very basic terminals where even the arrow keys don’t work). To delete a character, press X. To delete a whole line, press DD. To insert a new character, press I. This takes you into “insert mode,” and you can start typing. Press the Escape key when finished to go back to “command mode.” Within command mode, type :w to save (i.e. write) the file and :q to quit, or :wq to do both at the same time.

The vi editor also supports copying and pasting, undoing and redoing, searching and replacing, opening multiple files and copying between them, etc. To find out how, look for a good vi tutorial (such as “Mastering the VI Editor”). Note also that on many computers, vi is just a shortcut to vim, which stands for “vi improved,” so you can follow vim tutorials, too.

The Linux editor vi

Editing files with the vi text editor

More Advanced Tip: Tab Completion

When changing directories and editing files, you might get tired of having to type the file names in full over and over again. The Terminal loses some of its shine this way. This can be avoided with command-line completion, performed using tabs.

It works like this: start typing the name of a file or a command, and then press Tab. If there is only one possibility, Linux will fill in as much as it can. If nothing happens, it means there is more than one possibility. Press Tab again to show all of the possibilities.

For example, if above I had typed…

vi i

… And then pressed Tab, it would have filled in the rest for me…

vi index.php

… Unless several files started with I. In that case, I would have had to press Tab again to see the options.

Backing Up And Restoring Files And Databases

Some Linux servers do support the zip command, but all of them support tar, whose original purpose was to archive data to magnetic tapes. To back up a directory, specify the backup file name and the directory to back up, such as:

cd /var/www/vhosts/myserver.com/httpdocs/
tar czf /tmp/backup.tgz .

The czf means “create zipped file.” The single dot stands for the current directory. You can also back up individual files. To back up just things changed in the last day, add the find command:

tar cfz /tmp/backup.tgz `find . -type f -ctime -1`

Both of these commands put the actual backup file in the temporary /tmp directory — if the backup file is in the same directory that you are backing up, it will cause an error. You can move the file to where you need it afterwards. To see what is in an archive, use the tzf options instead:

tar tfz /tmp/backup.tgz

Linux tar command

Creating and showing the contents of a backup file using tar

To restore things, use xzf, for “extract from zipped file.” First, run a listing as above to check what’s in there, and then restore one or more of the files. The second command restores all of the files from the archive into the current directory:

tar xfz /tmp/backup.tgz ./index.php ./test.php
tar xfz /tmp/backup.tgz

If your server has the zip command, then run these commands to do the same thing:

cd /var/www/vhosts/myserver.com/httpdocs/
zip -r /tmp/backup.zip .
zip -r /tmp/backup.zip `find . -type f -ctime -1`
unzip -l /tmp/backup.zip
unzip /tmp/backup.zip test.php
unzip /tmp/backup.zip

If your Web server uses MySQL, then you might want to regularly back up your data. For this, there is the mysqldump command. The format of the command is:

mysqldump --user="username" --password="password" --add-drop-table database

Replace the user name, password and database with your values. Instead of specifying a database, you can use -A to dump all databases. If you get errors about table locking, you can add --single-transaction. Once you submit the user name and password, this will output a load of SQL in a long blur. To save the output to a file, you will need to use the > symbol. This sends the output of a command to a file.

mysqldump --user="username" --password="password" --add-drop-table database > /tmp/db.sql

To restore a database backup, you can use the mysql command. This command lets you run SQL statements from the command line. For example, the following command gets you into the database:

mysql --user="username" --password="password" dbname

At the mysql> prompt, you can type an SQL statement such as:

mysql> SHOW TABLES;
mysql> SELECT * FROM customers;

For restoring, you’ll need to use the pipe (|), which will send the output from one command into another. In this case, cat will output the database backup file and send it into the mysql command:

cat /tmp/db.sql | mysql --user="username" --password="password" dbname

If people are looking over your shoulder while you’re doing this, you might not want to type the password directly into the command. In this case, just leave it out, and mysql or mysqldump will ask for it instead.

cat /tmp/db.sql | mysql --user="username" --password dbname

Once you’ve created the database backup file, you can include it in the backups we did above:

tar czf /tmp/backup.tgz . /tmp/db.sql

More Advanced Tip: Hidden Files and Wildcards

Many websites use a file called .htaccess to implement URL rewriting and password protection. In UNIX, all files starting with a single dot are hidden. They won’t show up when you do ls, and they won’t get backed up if you do this:

tar czf /tmp/backup.tgz *

The * is a wildcard. Before the command executes, the * is replaced with all non-hidden files in the current directory. To include hidden files as well, it’s better to back up the whole directory as above using a single dot:

tar czf /tmp/backup.tgz .

To show hidden files when doing a directory listing, add -a to the command:

ls -a
ls -la

File Permissions

If you use FTP regularly to upload files to websites, then you might be familiar with permissions. All files and directories on Linux (and Mac, Windows and other UNIX systems) have an owner, a group and a set of flags specifying who can read, write and execute them.

The list of user names (and, thus, potential file owners) on a UNIX system is stored in the file /etc/passwd. You can try:

more /etc/passwd

The Apache Web server is started by a command when the Web server boots up. But the user who starts Apache is often a restricted and unprivileged user, such as nobody or apache or www-data. This is for security reasons, to prevent someone from hacking into the website and then gaining control of the whole server. You can find out who that user is by running the command below and looking in the first column. The ps aux command shows all of the processes running on the server, and grep shows only processes that contain the word “apache.”

ps aux | grep apache

This can cause conflicts, though. If you upload a file to a website via FTP and log in as admin, then the file will be owned by admin. If Apache was started by the user named nobody, then Apache might not be able to read that file and won’t be able to send it to any users who request it when viewing the website. Instead, users will see a broken image or a message such as “403 Forbidden. You don’t have permission to access that file.”

A subtler and more common problem is when an image can be viewed but not overwritten or removed via the website’s content management system (CMS). In this case, the user nobody can read the file but can’t write to it.

You can view permissions using the ls command with an extra -l, like so:

ls -l

ls command with long list format

The command ls -l shows information about permissions, owners, size and date.

This directory contains three files, with three subdirectories shown in green. The first letter on each line indicates the type: d for directory and - for normal file. The next nine letters are the permissions; they indicate the read, write and execute permissions for the owner, group and everyone else. After the number (which represents the size) is the owner and group for the file. These files are all owned by admin. This is followed by the file size (less useful for directories) and the date and time of the last modification.

Below is another example of three files in an images subdirectory. Two of the files were uploaded by admin via FTP, and Apache was started by the user www-data. One of the files will be unviewable through a Web browser. Which do you think it is?

Bad permissions

The answer is bg.jpg. Both bg.jpg and logo2.gif have the same permissions: only the owner can read and write them. The logo2.gif file is OK because the owner is www-data, so that file can be accessed, read and returned by Apache. The logo.gif file is also OK because it has r in all three permissions (i.e. owner, group and everyone else). But bg.jpg will fail because only the user admin can read it, not the user who started Apache. If you were to access that file in a Web browser, you would see something like this:

What happens when you try to access a file without the correct permissions in a browser.

These sorts of errors can be resolved with the chmod command, which changes file permissions. The three sets of permissions are represented in commands with u (“user” or owner), g (“group”), o (“other” or everyone else) or a (“all”). So, to enable all users to read bg.jpg, either of these would work:

chmod go+r images/bg.jpg
chmod a+r images/bg.jpg

If this file were also part of a CMS, then you’d have to also add write permissions before the CMS could overwrite it:

chmod a+rw images/bg.jpg

You can also make these changes to all files in all of the subdirectories by adding -R. This recursive operation is not supported by some FTP programs and so is a useful command-line tool:

chmod -R a+rw images/

Directories also need the x (“execute” permission), but files generally don’t (unless they are in a cgi-bin). So, you can give everything rwx (read, write and execute) permissions and then take away the x from the files:

chmod -R a+rwx images/
chmod -R a-x `find images/ -type f`

However, this does leave everything rather open, making it easier for hackers to gain a foothold. Ideally, your set of permissions should be as restrictive as possible. Files should be writable by the Apache user only when needed by the CMS.

More Advanced Tip: Chown and the Superuser

Another useful permissions command is chown. It changes the owner of a file. However, you have to be logged in as a user with sufficient privileges (such as root) in order to run it. To make www-data the owner of bg.jpg, run this:

chown www-data images/bg.jpg

This will probably return “Permission denied.” You have to run the command as the superuser. For this, you will need to find the root password for your server, and then run the following:

sudo chown www-data images/bg.jpg

You will definitely need to be the superuser if you want to edit configuration files, such as Apache’s:

sudo vi /etc/httpd/conf/httpd.conf

If you want to become the superuser for every command, run this:

su

This is dangerous, though, because you could easily accidentally remove things — especially if you are using the rm command, and particularly if you’re using it in recursive mode (rm -r), and most especially if you also force the changes and ignore any warnings (rm -r -f).

Conclusion

This article has introduced some very useful Linux commands, a potential asset for any aspiring Web worker and a surefire way to impress a dinner date.

For a few more commands related specifically to website crashes, check out the Smashing Magazine article “What to Do When Your Website Goes Down.” For a broader view, try this list of Linux commands. And the “Mastering the VI Editor” tutorial mentioned above explains vi well.

Hopefully, you now have the tools and confidence to pitch in the next time one of your websites has a problem.

(al)


© Paul Tero for Smashing Magazine, 2012.

How To Integrate Facebook, Twitter And Google+ In WordPress

without comments




  

Integrating social media services in your website design is vital if you want to make it easy for readers to share your content. While some users are happy with the social media buttons that come built into their design template, the majority of WordPress users install a plugin to automatically embed sharing links on their pages. Many of you will find that a plugin does exactly what you need; others not so much. Some are poorly coded, and most include services that you just don’t need. And while some great social media plugins are out there, they don’t integrate with every WordPress design.

The Big Three: Twitter, Facebook, and Google+

If you aren’t comfortable editing your WordPress templates, a plugin is probably the best solution. If you are comfortable making a few edits to your theme, then consider manually integrating social media so that you have more control over what services appear on your website.

Today, we’ll show you how to manually integrate the three most popular social media services on your website: Twitter, Facebook and Google+. First, you’ll learn how to integrate Facebook comments on your WordPress website, to make it easier for readers to discuss your posts. Then, we’ll show you the most common ways to display your latest tweets in the sidebar, which should encourage more people to follow you on Twitter. Finally, we’ll show you how to add sharing buttons for all three social media services to your home page, posts and pages.

Please make sure to back up all of your template files before making any changes, so that you can revert back if something goes wrong. Testing your changes in a non-production area first would also be prudent.

Integrate Facebook Comments On Your Website

Because most people are signed into Facebook when they browse the Web, enabling Facebook comments on your website is a great way to encourage people to leave comments. It also curbs spam. While many solutions purport to reduce spam comments on WordPress, most are either ineffective or frustrate visitors by blocking legitimate comments.

Feature-rich commenting solutions such as IntenseDebate and Disqus have benefits, of course, because they allow users to comment using Facebook and a number of other services; but before visitors can comment, they have to grant access to the application, an additional step that discourages some from commenting. By comparison, integrating Facebook comments directly enables visitors to comment with no fuss. Also, this commenting system allows users to comment by signing into Facebook, Yahoo, AOL or Hotmail.

Before integrating Facebook on WordPress Mods at the end of September, I looked at a few solutions. I followed a great tutorial by Joseph Badow and tried a few plugins, such as Facebook Comments For WordPress. The reality, though, is that the official Facebook comment plugin is the quickest and easiest way to add Facebook comments to your website.

Simply follow the steps below to get up and running.

1. Create a Facebook Application

To use Facebook comments on your website, create a new comment application for your website on the Facebook Application page. This step is required, whether you add Facebook comments manually using a third-party plugin or with the official Facebook plugin.

Simply click on the “+ Create New App” button on the Facebook Application page, and enter a unique name for your application in the “App Display Name” field. The “App Namespace” field doesn’t have to be filled in for Facebook comments (it’s used with the Facebook Open Graph Protocol).

Create Facebook App

You will then be provided with an “App ID/API key” and an “App secret key.” You don’t need to remember these numbers because the official Facebook comments plugin automatically inserts them into the code that you need to add to your website.

Create Facebook Application

2. Add the Code to Your Website

Next, go back to the Facebook Comments plugin page and get the code for your website. The box allows you to change the URL on which comments will be placed, the number of comments to be shown, the width of the box and the color scheme (light or dark).

Customise Facebook

You don’t have to worry about what you enter in the box because all of the attributes can be modified manually. And it doesn’t matter what URL you enter because we will be replacing it later with the WordPress permalink:

  • href
    The URL for this Comments plugin. News feed stories on Facebook will link to this URL.
  • width
    The width of the plugin in pixels. The minimum recommended width is 400 pixels.
  • colorscheme
    The color scheme for the plugin (either light or dark).
  • num_posts
    The number of comments to show by default. The default is 10, and the minimum is 1.
  • mobile (beta)
    Whether to show the mobile version. The default is false.

When you click on the “Get Code” button, a box will appear with your plugin code (choose the HTML5 option, because FBML is being deprecated). Make sure to select the application that you set up earlier for your comments so that the correct application ID is added to the code.

Get Facebook Application Code

Insert the first piece of code directly after the <body> tag in your header.php template:

<div id="fb-root"></div>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1&appId=YOURAPPLICATIONID";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

Put the second line of code where you want to show the comments. Make sure the static URL is replaced with the WordPress permalink (<?php the_permalink() ?>) so that comments show correctly on every page of your website.

<div class="fb-comments" data-href="<?php the_permalink() ?>" data-num-posts="15" data-width="500"></div>

To put Facebook comments above WordPress comments, add the above code just below the line that reads <!-- You can start editing here. --> in the comments.php template. To put Facebook comments below WordPress comments, add the above code below the </form> tag (again in the comments.php template).

If you plan to completely replace your WordPress comments with Facebook comments, simply replace the call to your comments.php template with the call to your Facebook comments. For example, to replace comments in posts, simply add the code to the single.php template. Similarly, edit the page.php template to show Facebook comments on pages.

Facebook Comments

Your should now see the Facebook comments box displayed on your website. To get an update whenever someone leaves a comment using Facebook, add yourself as a moderator to your application on the Comment Moderation tool page.

Show Your Latest Tweets In The Sidebar

Displaying your latest tweets is a good way to encourage people to follow you on Twitter. The most common place to display tweets is in the sidebar, although you can add them to any area of the website.

Display Your Latest Tweets Manually

I have tried a few manual solutions for showing tweets on my websites, and my favorite comes from Chris Coyier of CSS-Tricks. His RSS fetching snippet is a quick and effective way to show the latest tweets from your account. The RSS address of your Twitter account is http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=xxxxx (where xxxxx is your Twitter user name). For the tweets that you favorite, use http://twitter.com/favorites/xxxxx.rss. For example, the RSS for the latest tweets from Smashing Magazine is http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=smashingmag; and to display only the favorites, https://twitter.com/favorites/smashingmag.rss. Once you’ve got your Twitter RSS address, simply add it to Chris’ PHP snippet.

<?php
include_once(ABSPATH . WPINC . '/feed.php');
$rss = fetch_feed('https://api.twitter.com/1/statuses/user_timeline.rss?screen_name=smashingmag');
$maxitems = $rss->get_item_quantity(3);
$rss_items = $rss->get_items(0, $maxitems);
?>

<ul>
<?php if ($maxitems == 0) echo '<li>No items.</li>';
else
// Loop through each feed item and display each item as a hyperlink.
foreach ( $rss_items as $item ) : ?>
<li>
<a href='<?php echo $item->get_permalink(); ?>'>
<?php echo $item->get_title(); ?>
</a>
</li>
<?php endforeach; ?>
</ul>

For a more stylish way to display tweets manually, check out Martin Angelov’s tutorial “Display Your Favorite Tweets Using PHP and jQuery,” or Sea of Cloud’s “Javascript Plugin Solution.”

Display Your Latest Tweets Using the Official Twitter Widget

The official Twitter profile widget looks great and is easy to customize. You can define the number of tweets to display and whether the box should expand to show all tweets or provide a scroll bar.

The dimensions can be adjusted manually, or you can use an auto-width option. The color scheme can easily be changed in the settings area, too. Once the widget is the way you want it, simply grab the code and add it to the appropriate WordPress template.

Official Twitter Profile Widget

Display Your Latest Tweets Using a WordPress Plugin

If you don’t want to code things manually or use the official Twitter profile widget, you could try one of the many plugins available:

Add Social-Media Sharing Buttons To Your WordPress Website

Adding social-media sharing and voting buttons is very straightforward and enables readers to share your content on the Web. Simply get the code directly from the following pages:

The buttons you get from the above links work well when added directly to posts (single.php) and pages (page.php). But they don’t work correctly on the home page (index.php) or the archive (archive.php) by default, because we want to show the number of likes, pluses and retweets for each individual article, rather than the page that lists the article. That is, if you simply add the default code to index.php, every button will show the number of shares for your home page, not for each article.

To resolve this, simply make sure that each button uses the article permalink, rather than the URL of the page it is on. To add sharing buttons only to posts, simply choose the button you want from the links above and copy the code to single.php; to add the buttons only to pages, just add the code to page.php.

To show the number of likes, pluses and retweets that an article has on the home page and in the archives, follow the steps noted below for Facebook, Google+ and Twitter below (the code for showing a sharing button on the index page will work for posts and pages, too). You can see an example of sharing buttons integrated in post excerpts on my own website WordPress Mods and on popular blogs such as Mashable.

Social Media Sharing Buttons Example

Facebook

Facebook’s Like button comes with a lot of options. Choose from three layouts: standard, button count and box count. An email button (labelled “Send”) can be added, and you can set the width of the box, too. You can also show profile pictures below the button, choose between the labels “Like” and “Recommend,” choose between a light and dark color scheme, and set the font.

Customise Facebook

You need to add two pieces of code to your website. First, add the JavaScript SDK code directly after the <body> tag (in the header.php template). This code has to be added only once (i.e. if you’ve already added the code to show Facebook comments on your website, you don’t need to add it again).

Put the second piece of code where you want to show the Like button. To ensure that the correct page is referenced, add href="<?php echo get_permalink($post->ID); ?>" to the second piece of code. It should look something like this:

<div class="fb-like" data-href="http://www.facebook.com/smashmag" href="<?php echo get_permalink($post->ID); ?>" data-send="false" data-layout="box_count" data-width="450" data-show-faces="true" data-font="arial"></div>

More information on how to customize the Like button can be found on the Facebook Like Button page.

Google+

Google+ offers four sizes of sharing buttons: small, medium, standard and tall. The number of votes that a page has received can be shown inline, shown in a bubble or removed altogether.

Customise Google+

Linking to your article’s permalink is very easy. Just append href="<?php the_permalink(); ?>" to the g:plusone tag. For example, to show a tall inline Google+ button, you would use the following code:

<!-- Place this tag where you want the +1 button to render -->
<g:plusone size="tall" annotation="inline" href="<?php the_permalink(); ?>"></g:plusone>

<!-- Place this render call where appropriate -->
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>

For more tips on customizing the Google+ button, please view the official Google+ button documentation page.

Twitter

Twitter offers four types of buttons: one for sharing links, one for inviting people to follow you, a hash tag button for tweeting stories, and another for mentions (used for contacting others via Twitter). The button you need to show the number of shares that an article has gotten is called “Share a link.”

On the button customization page, you can choose whether to show the number of retweets and can append “Via,” “Recommend” and “Hashtag” mentions to the shared link.

Customise Twitter

To make sure Twitter uses the title of your article and the correct URL, simply add ata-text="<?php the_title(); ?>" and data-url="<?php the_permalink(); ?>" to your link. For example, if you were using the small button, you would use:

<a href="https://twitter.com/share" class="twitter-share-button" data-via="smashingmag" ata-text="<?php the_title(); ?>" data-url="<?php the_permalink(); ?>">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>

To show the larger button instead, simply append data-size="large" to the link. To show the popular vertical button (shown below) instead of the default horizontal button, append data-count="vertical" to the link.

Twitter Vertical Button

For more tips on customizing the Twitter button, please view the official Twitter button documentation page.

Summary

Many WordPress users continue to use plugins to integrate social-media sharing buttons and activity on their websites. As we’ve seen, though, integrating social-media services manually is straightforward and, for many users, a better solution than simply installing a plugin and making do with whatever features it offers.

Integrating Facebook comments on your website takes only a few minutes and is much less complicated than any of the available plugins. While good tutorials are available that show you how to manually add Twitter to your website, the official widget from Twitter is the best all-around solution for most websites.

Some fantastic plugins exist for WordPress to automatically insert social-media voting buttons in your design. Installing and setting them up takes only a few minutes, although manually adding the buttons enables you to give them maximum visibility.

Remember, play it safe and make any changes in a test area first before applying the changes to the live website. I also recommend backing up all of your template files before changing anything (and your database if required). A few minutes of preparation could save you hours of troubleshooting, so try not to skip this step.

Hopefully, you’ve found this useful. If you are unsure of any aspect of this tutorial, please let us know and we’ll do our best to clarify the step or help you with it. Also, subscribe to Smashing Magazine via RSS, Twitter, Facebook or Google+ to get the latest articles delivered directly to you.

(al)


© Kevin Muldoon for Smashing Magazine, 2012.

Written by Kevin Muldoon

January 19th, 2012 at 4:32 pm

Resolution Independence With SVG

without comments




  

In this article, we’ll look at Scalable Vector Graphics (SVG), one of the most underused technologies in website development today.

Before diving into an example, let’s consider the state of the Web at present and where it is going. Website design has found new vigor in recent years, with the evolving technique of responsive design. And for good reason: essentially, responsive website design moves us away from the fixed-width pages we’ve grown accustomed to, replacing them with shape-shifting layouts and intelligent reflowing of content. Add to that a thoughtful content strategy and mobile-first approach, and we’re starting to offer an experience that adapts across devices and browsers to suit the user’s context.

When we look at the breadth of Web-enabled devices, responsive design is sure to provide a better user experience. Scrolling horizontally, panning and zooming the viewport have their place in user interface design, but forcing the user to do these things just to navigate a website quickly becomes tedious. Fitting the website to the viewport is about more than just layout: it’s also about resolution. In this article, I’ll demonstrate why SVG is a perfect addition to future-friendly Web development.

Introducing SVG

SVG offers a truly resolution-independent technique for presenting graphics on the Web. SVG is a vector graphics format that uses XML to define basic properties such as paths, shapes, fonts and colors, and more advanced features such as gradients, filters, scripting and animation. Create the file once and use it anywhere, at any scale and resolution.

Consider the use cases: UI and navigation icons, vector-style illustrations, patterns and repeating backgrounds. For all of these, a scalable graphic is the perfect solution from a visual standpoint, and yet fixed-resolution images are still the norm. In the example below, we’ll show you how to expand on a common development technique to take advantage of SVG.

Resolution independence with SVG

A Case Study: CSS Sprites

We all know about the CSS sprites technique. (If you don’t, then have a quick read through Sven Lennartz’ article. And Louis Lazaris points out its pros and cons.) In the example below, we’ll show how seamlessly SVG replaces normal raster images. If this technique is not for you, you can certainly imagine a whole array of similar situations in which to use SVG.

Vector icons play a big role in user interface design. Pictures express concepts with vivid clarity, whereas their textual counterparts might carry ambiguity. In UI design, where space is scarce, a simple illustrated icon could be greatly welcome.

I’ve mocked up the following example:

An icon based UI menu

I’ll be first to admit that this row of icons won’t win any design awards, but it will suffice for the sake of this article! Let’s look at the HTML:

<div class="actions">
   <a class="a-share" href="#">Share</a>
   <a class="a-print" href="#">Print</a>
   <a class="a-tag" href="#">Tag</a>
   <a class="a-delete" href="#">Delete</a>
</div>

I’ve kept the HTML to a minimum for clarity, but in practice you’d probably want to mark it up with an unordered list. And you’ll almost certainly want to replace those hashes with real URLs (even if JavaScript provides the functionality, having a fallback is nice). Let’s look at the CSS:

.actions {
   display: block;
   overflow: auto;
}

.actions a {
   background-image: url('sprite.png');
   background-repeat: no-repeat;
   background-color: #ccc;
   border-radius: 5px;
   display: block;
   float: left;
   color: #444;
   font-size: 16px;
   font-weight: bold;
   line-height: 20px;
   text-decoration: none;
   text-shadow: 0 -1px 2px #fff;
   padding: 10px 20px 10px 40px;
   margin-right: 5px;
}

.a-share  { background-position: 10px 0; }
.a-print  { background-position: 10px -40px; }
.a-tag    { background-position: 10px -80px; }
.a-delete { background-position: 10px -120px; }

Note the fixed-pixel sizing and the PNG background, which we can see below framed in full Photoshop production glory:

A PNG sprite in Photoshop

This implementation of a CSS sprite is basic, and at today’s standard, it’s not good enough! How can we enhance this? First, let’s consider the following issues:

  1. We’ve rasterized the image at a very early stage. Even at full size, icons in which points sit between pixels, such as the one for “Print,” have blurred.
  2. If we zoom in, the image will blur or pixellate even more; there is no additional data to re-render the image at larger sizes.
  3. Everything has a fixed size, which is neither good for responsive design nor good for accessibility, because the browser’s default font size is ignored.

As you’ve probably guessed by now, we’ll show you how SVG solves these problems. But first, let’s reiterate each point thoroughly to understand the issues at large.

1. Rasterization

Devices such as modern smartphones have a very high pixel density; some already surpass the 300 pixels-per-inch (PPI) mark that is assumed to be the limit of the human eye’s ability to distinguish fine details. A pixel has no real-world equivalent in size until it sits on a screen of fixed dimension (say, 3.5 inches diagonally) and fixed resolution (say, 640 × 960 pixels). At this scale, text with a font size of 16 pixels would be incredibly small to the eye. For this reason, devices simply cannot translate 1 CSS pixel unit to 1 device pixel; instead, they double up. Thus, a 16-pixel font size actually takes over 32 pixels when rendered.

The same applies to images; but they are already rasterized, so doubling up the pixels has no benefit. In our example, each icon has been rasterized at around 25 × 25 pixels (the whole sprite being 30 × 160), so they cannot take advantage of the double pixel ratio. One solution is to use CSS media queries to detect the pixel ratio. This is already implemented in Webkit- and Gecko-based browsers.

To improve our example, we can add the following CSS declaration:

@media only screen and (-webkit-min-device-pixel-ratio: 2)  {
   .actions a {
      background-image: url('sprite@2x.png');
      background-size: 30px 160px;
   }
}

The alternate background image supplied in the code above has been saved at 60 × 320 pixels (i.e. double the original dimensions). The background-size property tells CSS to treat it smaller. Significantly, now the device has the additional data to render a better image (if capable).

This solution isn’t bad, but it doesn’t solve the problems we’ll run into in points 2 and 3 below. It also requires that we maintain multiple files of increasing size: a potential burden on bandwidth and a real hassle. For non-vector images, such as photography in JPG format, we can’t do much more than that.

2. Zooming

At their default size, our rasterized icons look acceptable, at least on low-pixel-density screens. However, should the user zoom in on the Web page, these little UI delights will degrade very quickly.

A PNG sprite zoomed in and blurred.

Zooming is a common action when users find a website too small for comfortable viewing. Or, to put it another way, websites that are designed too small are very common. There is really no “perfect” size, because almost everyone has at least some level of visual impairment, since our eyes inevitably deteriorate with age. Secondly, with the rapid increase in touchscreen devices, pinch-to-zoom has become the standard way to enlarge fixed-sized content designed for larger screens (i.e. much of the Web today).

We should develop websites in a way that minimizes the need for user input — that’s where responsive design comes in (see point 3 below) — but zooming is here to stay. There’s simply no way to provide pre-rasterized images for every level of zoom (in theory, an infinite scale). Scalable graphics are the solution, and we’ll show you how to enhance our example. But first, a related word on fixed sizing.

3. Fixed Sizes

Presenting page elements at fixed sizes forces many users to zoom, but it also disables a very useful browser feature. Users can set their preferred font size (the default in browsers is 16 pixels). By sizing everything in pixels, we override this preference. Sizing elements based on this default is much better, so that, if the text is bigger, everything adjusts to match. This essentially mimics the zooming effect but happens without the user having to manually do it on every visit. Ethan Marcotte has written a great article that explains relative font sizes.

Let’s re-implement our sprite example with a solution to these three issues.

A Scalable Implementation

Here is the HTML again. We don’t need to change anything here.

<div class="actions">
   <a class="a-share" href="#">Share</a>
   <a class="a-print" href="#">Print</a>
   <a class="a-tag" href="#">Tag</a>
   <a class="a-delete" href="#">Delete</a>
</div>

The updated CSS is where the magic happens:

body { font-size: 100%; }

.actions {
   display: block;
   overflow: auto;
}

.actions a {
   font-size: 1em;
   line-height: 1.25em;
   padding: 0.625em 1.25em 0.625em 2.5em;
   margin-right: 0.3125em;
   border-radius: 0.3125em;
   background-image: url('sprite.svg');
   -webkit-background-size: 1.875em 10em;
   -o-background-size: 1.875em 10em;
   -moz-background-size: 1.875em 10em;
   background-size: 1.875em 10em;
   /* styles carried over from the original implementation */
   background-repeat: no-repeat;
   background-color: #ccc;
   color: #444;
   display: block;
   float: left;
   text-decoration: none;
   text-shadow: 0 -1px 2px #fff;
}

.actions-em .a-share { background-position: 0.625em 0; }
.actions-em .a-print { background-position: 0.625em -2.5em;  }
.actions-em .a-tag { background-position: 0.625em -5.0em;  }
.actions-em .a-delete { background-position: 0.625em -7.5em;  }

In this version, we’ve made the following changes:

  • The background-image is now an SVG file.
  • All sizes are based on the default of 16 pixels, or 1 em. If the user’s default is larger or smaller, then everything will scale relatively. (If you multiple each em size by 16, you’ll get the number of pixels used in our initial fixed-size example.)
  • The background-size is very important. By setting this in em units, we’re telling the browser to scale the sprite relative to everything else. You’ll notice that 1.875 × 10 em multiplied by 16 becomes 30 × 160 — the base size at which we produced the sprite in pixels.
  • The background-position of each sprited icon is also based on relative units.

Now that we’re using SVG and relative sizes, we have solved the three big issues highlighted above. A scalable graphic can be rasterized on demand to perfectly suit any device resolution and any zoom level. By using relative sizes, we can continue implementing a responsive design, minimizing as much as possible the need for the user to zoom. We’re also respecting the browser’s default font size, and enabling our design to adapt accordingly.

I actually produced the SVG sprite first and the PNG version from that. (I imported the SVG in Photoshop before exporting it as a PNG — Illustrator’s PNG export had very poor rasterization.) Below is the header in my SVG file. Notice the same 30 × 160 initial size.

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
   width="30px" height="160px" viewBox="0 0 30 160" enable-background="new 0 0 30 160" xml:space="preserve">

You can see that the attributes for width and height are set in pixels (width="30px" height="160px") in the opening svg tag (as generated by Adobe Illustrator). This actually causes it to render early in Firefox, before the graphic has scaled to match the em sizes in background-size. Webkit-based browsers seem to scale the SVG perfectly, regardless. I’ve found that editing the SVG file to use em units in these two attributes fixes any rendering issues in Firefox.

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
   width="30em" height="160em" viewBox="0 0 30 160" enable-background="new 0 0 30 160" xml:space="preserve">

I don’t know which browser actually implements this scaling correctly, but let it be noted that extra care is needed to ensure cross-browser perfection. Mozilla MDN has an excellent in-depth article, “Scaling of SVG Backgrounds,” which explores more practical examples. For more ideas, see Alex Walker’s article “A Farewell to CSS3 Gradients.”

Here’s a super-close screenshot showing the SVG sprite:

A close-up of a SVG sprite.

The sprite scales beautifully. (Sadly, the same can’t be said for my tacky text-shadow effect.)

It’s best to experience the joys of scalable graphics and relative sizing firsthand. I’ve uploaded a side-by-side live demo demonstrating a combination of all the techniques mentioned above.

Browser Support

At the start of this article, I said that SVG was underused. I believe that has generally been the case due to poor browser support. But things are different now! Browser support for SVG has blossomed over the last year to the point where implementing it is a viable use of development time.

According to the website When Can I Use?, support for SVG across multiple implementations is as follows (I’ve combined support for both CSS’ background-image and HTML’s img source — the most useful attributes):

  • Internet Explorer 9+
  • Firefox 4+
  • Chrome 4+
  • Safari 4+
  • Opera 9.5+

Mobile browser support is also pretty much across the board. If a workable fallback exists for older browsers, then SVG is a very viable solution.

For some of the new additions to Web standards, we can implement them safe in the knowledge that old browsers will simply ignore them and that they aren’t even required. We call this “progressive enhancement”: better browsers get a progressively better experience. SVG is slightly different, because for most practical purposes, it simply replaces other images in CSS backgrounds and HTML elements. The image format — be it SVG, PNG, JPG or GIF — is either supported or it isn’t. We can’t simply follow the practice of progressive enhancement here, because an image failing to render is not an acceptable experience.

Browser Sniffing or Feature Detection?

We could make an educated guess and say that we need to worry only about users of Internet Explorer 6 to 8. In this case, the conditional comments technique for IE-only styles enable us to re-apply a second CSS background-image of a supported format such as PNG, instead of the default SVG background.

Browsing sniffing is always a dangerous game. While Internet Explorer tends to be the main offender, we can never assume it is the only one.

The safer and highly recommended option is to detect SVG support and use it only if it’s found. I suggest using Modernizr if you need to detect multiple features. Modernizr applies a class of svg to your root html element if detected (to which you can apply SVG as a background-image). If you’re using SVG as the source of an image element in HTML, then implementation is a little harder. You’ll have to write more JavaScript to find and replace all sources once support has been established.

The problem with these methods is that the browser will download the fallback image before SVG is detected — the only exception being the conditional comments technique for IE. Users will also likely see a flash of re-styled content when the source image changes. This shouldn’t be the case for long; but at least for now, these problems may be enough to hold you off on SVG usage.

File Size

In our sprite example, the raw SVG file was 2445 bytes. The PNG version was only 1064 bytes, and the double-sized PNG for double-pixel ratio devices was 1932 bytes. On first appearance, the vector file loses on all accounts, but for larger images, the raster version more quickly escalates in size.

SVG files are also human-readable due to being in XML format. They generally comprise a very limited range of characters, which means they can be heavily Gzip-compressed when sent over HTTP. This means that the actual download size is many times smaller than the raw file — easily beyond 30%, probably a lot more. Raster image formats such as PNG and JPG are already compressed to their fullest extent.

Performance

Rendering performance is a concern with SVG, especially on mobile devices, whose hardware is limited. Raster images can be rendered pixel for pixel after decompression and de-encoding. Vector graphics need to be rasterized at a specific resolution every time they’re viewed.

SVG has consistently proved slower than Canvas as a platform for animating vector graphics; but our concern here is basic rendering, not manipulation a thousand times per second, and if that is possible, then simple rendering shouldn’t be a concern. The more intensive SVG features are things like clipping masks and filter effects. These are unnecessary for many practical purposes (like our sprite example), but, if required, the best way to check performance is by testing. A lot of Web development is supported in theory, but in practice results are far from perfect.

Alternative Methods

Hopefully you agree that SVG is extremely useful but not always the ideal solution to resolution independence. Ultimately, the trick is to avoid raster images while maintaining the scalability of visual styles. Below are a few more ideas to think about.

CSS3

You’ve probably already started combining CSS3 properties such as linear-gradient, text-shadow and box-shadow to create more complex styles. Web developer Lea Verou curates a CSS3 pattern gallery that shows off the impressive potential of gradients alone.

CSS3 gradient patterns

In his article “Mobile Web in High Resolution,” Brad Birdsall introduces a technique to maintain pixel perfection for high-resolution displays using the pixel-ratio property.

Then there are pure CSS “icons,” which Faruk Ate? rightly points out as being absolute “madness” — certainly so if you’re using CSS to create a logo! But you could argue the benefits of a small handful of very specific techniques, such as CSS triangles, as demoed by Chris Coyier.

Web Fonts

Dingbat Web fonts and look-a-like Unicode glyphs are two interesting alternatives for vector icons, both with accessibility and semantic challenges. Jon Hicks has a write-up of perhaps the best practice for this. SVG seems a more appropriate technique for icons, but both have an immediate visual impact at high resolutions — and we’ll be paying increasing attention to that in coming years.

Looking Forward

As you can see, SVG usage is very much a possibility, and browser support and performance will only improve in future. What’s important to note from this article is that we really should be building websites that are as resolution-independent as possible.

Consider the “one Web” philosophy and the vast range of devices we use to access it — there is no single user experience. The more we can do to stay device-agnostic, the better. Responsive website design addresses many of these needs and certainly provides many benefits. Using vector graphics may not be as apparent, but its little improvements really do make a difference.

With today’s level of support, many users can experience the beauty of crisp scalable graphics… or perhaps that’s the wrong way to think about it. Most users won’t say “Wow! Kudos on the vectors.” To our dismay, they probably wouldn’t even consider them (and certainly wouldn’t recognize the effort required to craft them). And that’s a good thing; each time we improve the user’s experience, we don’t necessarily need to make a song and dance about it. Letting things continue to grind away under-appreciated is OK. It’s the lack of such things that gets recognized and sniffed at. Raise the user’s expectations in visual aesthetics, and they’ll start to notice the websites that do look shoddy. If you don’t do it, others will.

(al)


© dbushell for Smashing Magazine, 2012.