Friday, January 10, 2014

Where the best designers go to find photos and graphics

find photos and graphics

I'll let you in on a little secret: beautiful websites aren't made, they're found. Smart designers know where to find that perfect photo, subtle pattern or that unique icon.

Here's where the best designers go to find photos, graphics, icons and more.

Stunning Photography

Photography is what separates a good website from a great website. There may be no better example of great photography than Apple's website. Apple loves to showcase products with huge, eye popping photography. It's a great example of how to use photos.

Here's where the best designers find photos:

  • New Old Stock Photos - Awesome vintage photos from public archives. Completely free of known copyright restrictions.
  • New Old Stock Photos
  • Super Famous - Lots of geological, biological and aerial photography from from Dutch interaction designer Folkert Gorter. Sound boring? It's not. These photos are one of a kind.
  • Unsplash - A free email newsletter stuffed with hi-resolution photos. Sent every ten days.
  • Little Visuals - Another free email newsletter. Sends weekly batches of 7 gorgeous photos.
  • Comp Fight - The fastest way to find Creative Commons images to use on your blog or website.
  • Pic Jumbo - Big, searchable database of totally free to use photos.

Sample photo from Pic Jumbo

Sharp Icons

The next time you're browsing Facebook, Google or Twitter, take note of how many icons you'll see. They're everywhere. That's because icons are an essential part of web design.

Here's where smart graphic designers go to find icons:

  • The Noun Project - The grand daddy. Enormous database of over 25,000 icons and growing daily. Each icon has a similar format so they always look professional and consistent.
  • Icons from The Noun Project
  • Icon Monstr - Free, simple icons discoverable through a search interface. Over 2,000 icons.
  • Icon Sweets - Love iOS7? This downloadable library has over 1,000 icons in the style of iOS7 (iOS7 is known for having outlined icons). Available for only $10.

Graphics & Logos

  • Creative Market - Amazing, handcrafted graphics from designers around the world. I always find top-rate stuff here.
  • Creative Market
  • 99 Designs - Crowdsource your logo: hold a contest and have 20 – 30 designers submit logo entries. Choose the one you like.
  • Scoop Shoot - Need photos from around town? ScoopShoot lets you hire people around town to take photos with their phones.
  • Subtle Patterns - Over 369, subtle (duh) patterns. They all work by being repeated, so they're perfect for websites.
  • Subtle Patterns
  • Colour Lovers - Have difficulty choosing which colours to use? Colour Lovers has literally millions of colour palettes created by users that are ready for you to use.

Two tools that will make you a design rockstar

  • Pixlr - Pixlr is like a free, online version of Photoshop.
  • Placeit - An incredible website. Just drag and drop screenshots and it will generate shots of your screenshot in realistic environments.

Placeit – Just upload a screenshot and Placeit will automatically place it in a new context

Bonus: Reader submitted resources

Savvy readers have mentioned additional tools that I hadn’t included. Here’s some that have stuck out to me:

  • Gimp – A bit of a learning curve, but a free tool for image editing (Thanks to Jesus Bejarano and Rekasays in the comments section).
  • Creative Commons images on Flickr – Thanks to 3stripe on Hacker News.

Friday, January 10, 2014

Sticky Table Headers & Columns

Sticky Table Headers & Columns

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

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

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

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

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

A Pure CSS-Based Solution with position: sticky?

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

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

The jQuery Based Solution

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

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

What do we want to achieve?

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

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

Some CSS groundwork

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

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

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

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

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

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

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

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

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

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

Step 1: Clone the <thead> element

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

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

Step 2: Wrap table and append new tables

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

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

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

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

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

Step 3: Inserting cloned table contents

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

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

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

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

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

Step 4: Functions

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

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

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

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

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

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

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

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

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

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

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

        return a;
    };
}

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

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

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

Step 5: Fire away, fire away!

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

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

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

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

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

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

And voila, you're done!

Discussion

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

Why don't you use position: fixed?

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

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

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

Why don't you use position: sticky?

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

View Demo

Thursday, January 09, 2014

CSS Blend Modes could be the next big thing in Web Design

CSS Blend Modes could be the next big thing in Web Design
Cool-looking things that are difficult or downright impossible to replicate in CSS right now. Top row: Doublenaut, Graham Hicks, Jonathan Quintin and Geoff Teehan. Bottom row: Ben Johnson, Claire Morales, Alan Defibaugh and Jess Barlow

For everyone who has ever opened Photoshop or Illustrator you are most likely familiar with blend modes. Multiply, screen, overlay and soft light, to name a few can turn boring opaque layers into beautiful pieces of stained glass. However, what awesome "blend modes" do web designers have at their disposal for making websites beautiful? Opacity. Yep, that's it.

Blend modes and the web

It's a shame that we couldn't have had more blend modes to work with when the opacity property gained widespread support across browsers, but it turns out that ensuring Photoshop-like blend modes render uniformly across different browsers and implementations is no easy task. Some blend modes have been available in SVG through filters, but these are limited and don't see much use in the real world.

Despite this, things are changing fast and there is a draft specification titled CSS Compositing and Blending. Blend modes in CSS are being promoted heavily by Adobe Web Platform team (along with other interesting features like CSS regions and shaders).

Right now, the specification brings three brand new properties to CSS, background-blend-mode, mix-blend-mode and isolation. Let's explore!

Canvas 2D: Will it blend?

CSS Blend Modes could be the next big thing in Web Design - Canvas
Particles by Justin Windle.
Blend modes make this awesome demo really pop

First, here's a little secret, blend modes are now available for use with HTML5 Canvas in all the latest browsers except Internet Explorer. They are even supported on mobile Safari and Chrome. However, why should we stop there? Blend modes would be incredibly useful in CSS.

Blending in CSS: Say hello to background-blend-mode

CSS Blend Modes could be the next big thing in Web Design
Sixteen blend modes are coming to CSS. Demo.

The new background-blend-mode property allows you to specify blending between background layers of an element. Whether it be between an element's background-color and background-image, or a background-image CSS gradient, background-blend-mode mixes all the backgrounds together with the blend mode(s) you specify.

CSS Blend Modes could be the next big thing in Web Design
Medium even uses blend modes in their articles. Too bad our friend CSS isn't there to make this process a lot faster and easier.

Don't think this property would get much use? Don't go further than the website you're on right now. When uploading full-page backgrounds to an article, Medium gives you the option to apply a color to the background to make the title stand out a bit more. However, because browsers don't have blend modes in CSS, Medium has to do this the slow and costly way. They make six copies of the image you upload with different colors applied to each one, a process done on the server side. For the reader, this method is a lot slower than it could be with background-blend-mode. This new property could also be utilized elsewhere:

CSS Blend Modes could be the next big thing in Web Design - The Verge
The Verge's website is unique partly because of the pseudo blend modes they apply on their headlines. background-blend-mode could likely be used to make these kind of effects even better.

The super duper mix-blend-mode property

While background-blend-mode is strictly for blending backgrounds, we'd ideally also like to blend HTML and SVG elements like layers on a .psd. Fortunately, that is where the mix-blend-mode property comes in.

mix-blend-mode will blend elements with their backdrop. Perhaps you could experiment with a header that utilizes the screen blend mode rather than a simple background color with rgba(). There are also probably an infinite number of possibilities with loading animations and blend modes. The isolation property stops elements with mix-blend-mode from blending with the backdrop.

Implementation of the mix-blend-mode property is more complex than background-blend-mode so it is taking a bit more time, but don't let that get you down. Blend modes will be here soon!

Can I use blend modes now?

Not yet, but I would expect in 2014 you could be able to start. The specification has already been approved by the SVG working group and it needs approval from the CSS working group also to become a Candidate Recommendation. Once this happens soon, you can expect browsers to start shipping blend modes to browsers.

As for implementation, here's a brief summary: (Early January 2014)

  • Firefox: Implements background-blend-mode in version 29 but with bugs (see this demo) which they are working on. The mix-blend-mode property can be enabled in about:config.
  • Safari: Implements background-blend-mode in Webkit Nightly. Not mix-blend-mode.
  • Chrome and Opera: mix-blend-mode and background-blend-mode can be enabled in chrome://flags or opera://flags under "Experimental Web Platform Features".
  • Internet Explorer: Doesn't even support blend modes in Canvas. Can't find any info on current development of CSS blend modes.

Learn more


Thursday, January 09, 2014

WordPress Tutorial: What’s New in WordPress 3.8

What’s New in WordPress 3.8

WordPress 3.8 is here and there are a lot of exciting changes. Get up to date with the new features and start enhancing your blog or website today. In this video, lynda.com author Morten Rand-Hendriksen reveals the redesigned dashboard, which is high contrast, clean and more customizable than ever and the new Twenty Fourteen theme, which provides a (highly requested) featured content area on your front page. The new dashboard is also fully responsive, so you can now visit the dashboard from your mobile device. This is great for making changes on the go!



Magazine Theme

The magazine theme is a page layout for WordPress (a "theme") that mimics the layout of a newspaper or magazine, with multiple boxes and spaces for photographs, allowing for certain posts to be called out.

Look and feel

In software design, look and feel is a term used in respect of a graphical user interface and comprises aspects of its design, including elements such as colors, shapes, layout and typefaces (the "look"), as well as the behavior of dynamic elements such as buttons, boxes and menus (the "feel"). The term can also refer to aspects of an API, mostly to parts of an API that are not related to its functional properties. The term is used in reference to both software and websites.

Look and feel applies to other products. In documentation, for example, it refers to the graphical layout (document size, color, font, etc.) and the writing style. In the context of equipment, it refers to consistency in controls and displays across a product line.

Look and feel in operating system user interfaces serves two general purposes. First, it provides branding, helping to identify a set of products from one company. Second, it increases ease of use, since users will become familiar with how one product functions (looks, reads, etc.) and can translate their experience to other products with the same look and feel.

Some Popular WordPress Magazine Themes From ThemeForest


Thursday, January 09, 2014

5 Frontend Frameworks and Libraries You Should Know

5 Frontend Frameworks and Libraries You Should Know

Most of us have heard about awesome front-end frameworks like Bootstrap and Foundation and well as many libraries that help the rapid prototyping and/or development of a web site or a web app.

Thursday, January 09, 2014

jQuery and CSS3 Magnifying Glass for Images

jQuery and CSS3 Magnifying Glass for Images
Have you ever want to add a super cool effect to your site of product images and couldn't find a perfect match? I bet these magnifying glass effect should fits in any layout.

These magnifying glass is created using CSS3 box-shadow and border-radius properties. jQuery is used to position it at the cursor coordinates and change the background-position accordingly. Moving the cursor away from the image gently fades out the magnifying glass bringing the image back to the default state. The idea of this post is generated from the walkthrough of Thecodeplayer.

View Demo

<img class="magniflier" src="image.jpg" width="160"/>

Having the class magniflier is important, as it is what our Javascript code is going to check for and we have set a value of 160 to scale down the image size before the hovering.

.glass {
  width: 170px;
  height: 170px;
  position: absolute;
  border-radius: 50%;
  cursor: crosshair;
  
  /* Multiple box shadows to achieve the glass effect */
  box-shadow:
    0 0 0 7px rgba(255, 255, 255, 0.85),
    0 0 7px 7px rgba(0, 0, 0, 0.25), 
    inset 0 0 40px 2px rgba(0, 0, 0, 0.25);
    display: none;
}

The glass effect is simply achieved with basic CSS3 shadows and rounded corners and we have set the display to none so as to keep the glass invisible until it's hovered-on.

$(function() {

  var native_width = 0;
  var native_height = 0;
  var mouse = {x: 0, y: 0};
  var magnify;
  var cur_img;

  var ui = {
    magniflier: $('.magniflier')
  };

  // Connecting to the magnifying glass
  if (ui.magniflier.length) {
    var div = document.createElement('div');
    div.setAttribute('class', 'glass');
    ui.glass = $(div);

    $('body').append(div);
  }

  
  // All the magnifying will happen on "mousemove"

  var mouseMove = function(e) {
    var $el = $(this);

    // Container offset relative to document
    var magnify_offset = cur_img.offset();

    // Mouse position relative to container
    // pageX/pageY - container's offsetLeft/offetTop
    mouse.x = e.pageX - magnify_offset.left;
    mouse.y = e.pageY - magnify_offset.top;
    
    // The Magnifying glass should only show up when the mouse is inside
    // It is important to note that attaching mouseout and then hiding
    // the glass wont work cuz mouse will never be out due to the glass
    // being inside the parent and having a higher z-index (positioned above)
    if (
      mouse.x < cur_img.width() &&
      mouse.y < cur_img.height() &&
      mouse.x > 0 &&
      mouse.y > 0
      ) {

      magnify(e);
    }
    else {
      ui.glass.fadeOut(100);
    }

    return;
  };

  var magnify = function(e) {

    // The background position of div.glass will be
    // changed according to the position
    // of the mouse over the img.magniflier
    //
    // So we will get the ratio of the pixel
    // under the mouse with respect
    // to the image and use that to position the
    // large image inside the magnifying glass

    var rx = Math.round(mouse.x/cur_img.width()*native_width - ui.glass.width()/2)*-1;
    var ry = Math.round(mouse.y/cur_img.height()*native_height - ui.glass.height()/2)*-1;
    var bg_pos = rx + "px " + ry + "px";
    
    // Calculate pos for magnifying glass
    //
    // Easy Logic: Deduct half of width/height
    // from mouse pos.

    // var glass_left = mouse.x - ui.glass.width() / 2;
    // var glass_top  = mouse.y - ui.glass.height() / 2;
    var glass_left = e.pageX - ui.glass.width() / 2;
    var glass_top  = e.pageY - ui.glass.height() / 2;
    //console.log(glass_left, glass_top, bg_pos)
    // Now, if you hover on the image, you should
    // see the magnifying glass in action
    ui.glass.css({
      left: glass_left,
      top: glass_top,
      backgroundPosition: bg_pos
    });

    return;
  };

  $('.magniflier').on('mousemove', function() {
    ui.glass.fadeIn(100);
    
    cur_img = $(this);

    var large_img_loaded = cur_img.data('large-img-loaded');
    var src = cur_img.data('large') || cur_img.attr('src');

    // Set large-img-loaded to true
    // cur_img.data('large-img-loaded', true)

    if (src) {
      ui.glass.css({
        'background-image': 'url(' + src + ')',
        'background-repeat': 'no-repeat'
      });
    }

    // When the user hovers on the image, the script will first calculate
    // the native dimensions if they don't exist. Only after the native dimensions
    // are available, the script will show the zoomed version.
    //if(!native_width && !native_height) {

      if (!cur_img.data('native_width')) {
        // This will create a new image object with the same image as that in .small
        // We cannot directly get the dimensions from .small because of the
        // width specified to 200px in the html. To get the actual dimensions we have
        // created this image object.
        var image_object = new Image();

        image_object.onload = function() {
          // This code is wrapped in the .load function which is important.
          // width and height of the object would return 0 if accessed before
          // the image gets loaded.
          native_width = image_object.width;
          native_height = image_object.height;

          cur_img.data('native_width', native_width);
          cur_img.data('native_height', native_height);

          //console.log(native_width, native_height);

          mouseMove.apply(this, arguments);

          ui.glass.on('mousemove', mouseMove);
        };


        image_object.src = src;
        
        return;
      } else {

        native_width = cur_img.data('native_width');
        native_height = cur_img.data('native_height');
      }
    //}
    //console.log(native_width, native_height);

    mouseMove.apply(this, arguments);

    ui.glass.on('mousemove', mouseMove);
  });

  ui.glass.on('mouseout', function() {
    ui.glass.off('mousemove', mouseMove);
  });

});

Conclusion

Read through every attribution for better understanding of what operation each line performed.

  • Use the class magniflier to enable the effect on any image.
  • Attach data-large="image.jpg" to the HTML markup if you want to use different image for the zoomed version.

Now you have a simple-to-use magnifying glass plugin for your next project.

Thursday, January 09, 2014

45 Useful JavaScript Tips, Tricks and Best Practices

45 Useful JavaScript Tips, Tricks and Best Practices
As you know, JavaScript is the number one programming language in the world, the language of the web, of mobile hybrid apps (like PhoneGap or Appcelerator), of the server side (like NodeJS or Wakanda) and has many other implementations. It's also the starting point for many new developers to the world of programming, as it can be used to display a simple alert in the web browser but also to control a robot (using nodebot, or nodruino). The developers who master JavaScript and write organized and performant code have become the most sought after in the job market.

Tuesday, January 07, 2014

50 Free Graffiti Fonts for Designers

Free Graffiti Fonts - Inner City

In recent decades, graffiti has moved from an urban nuisance to a professional business - thanks to the work of some incredible street artists. And with the art form ever growing in popularity, there are now tons of graffiti font styles available online for creatives use in urban artwork.

Monday, January 06, 2014

What is the DOM?

What is the DOM?

But the HTML you write is parsed by the browser and turned into the DOM.

Monday, January 06, 2014

5 .htaccess Snippets to Borrow from HTML5 Boilerplate

htaccess Snippets
HTML5 Boilerplate is an awesome website template when you want all best pieces in place for you when you start your project. A while back I covered 7 CSS Snippets to Borrow from HTML5 Boilerplate, so today I want to feature a few .htaccess settings which could speed up, secure and make your site very much more useful!