All posts by Braad

Saving Shortcode Data in Meta in WordPress

Shortcodes in WordPress can be very powerful, but there is one fundamental thing about them that isn’t so great – they keep their data relatively inaccessible by storing it in post content. This makes it difficult to do something like query for all posts that have a specific shortcode with a specific attribute, or to efficiently batch request API calls that several shortcodes in a single post might need to make.

One solution I’ve found for this is to save shortcode data (all shortcodes and their attributes) in a meta key whenever a post is created or updated. This allows you to simply inspect this meta key and do whatever you need to do with the data without having to parse the shortcodes with regex. Luckily there are several helper functions in WordPress core that will help you do this. The get_shortcode_regex() function will give you a regex pattern that will match all the shortcodes you have registered and the shortcode_parse_atts() function will extract all the attributes into an array. By combining these we can create a function that accepts a string of content and returns all the shortcodes and their attributes found in the content.

However, one big challenge with shortcodes is that they don’t natively support nesting the way HTML elements do. A string of shortcodes like [title text="Hello"][title text="World"][/title][/title] would fail to be parsed correctly because the first closing [/title] would close the first [title text="Hello"] shortcode, and for a string like [title text="Hello"][sub_title text="World"][/sub_title][/title] only the outer [title text="Hello"] shortcode would get expanded. This happens because the regex used by WordPress Core to expand shortcodes will only search one level deep in a single pass. Although you can add specific support for nesting shortcodes of different types by calling do_shortcode( $content ) when expanding the $content param that gets passed to your shortcode callback functions, the core regex for searching for shortcodes does have this nesting limitation.

The use case of nesting the same type of shortcode is probably always going to be a bad idea until WordPress Core supports it (unlikely), but nesting of different types of shortcodes is much less problematic and much more common (because two different closing tags like [/sub_title][/title] can be distinguished). An ideal shortcode parsing solution would therefore be able to extract shortcodes and their attributes even when they are nested like this, and ideally this parsing would be done as efficiently as possible (once per blob of content rather than once per shortcode).

After playing around with this problem for a while I’ve got a working solution that I’m ready to share. It comes in two pieces. One piece is a function that gets passed an array or string of content and does the actual shortcode data extracting, and the other is a function hooked on the save_post action that calls the shortcode data extraction function and passes the clean array of shortcode data to a hook. Passing the data to a hook is key, because it allows for all of the parsing to happen once and pick up all the data for all the registered shortcodes, then any other code that wants to do something special with the data from a particular shortcode can hook in and manipulate a specific meta key from there, or you can hook in there and just save all the data under a single meta key.

Here is what the two pieces look like:

<?php

add_action( 'save_post', 'xxx_extract_shortcode_atts', 10, 3 );
/**
 * Extract all shortcodes and their attributes, build a usable array with this
 * data, and pass this to a hook so other code can handle saving values in meta.
 *
 * @param  int      $post_id  The post ID being saved.
 * @param  WP_Post  $post     The post object being saved.
 * @param  bool     $update   Whether the post is being created or updated.
 */
function xxx_extract_shortcode_atts( $post_id, $post, $update ) {

	if ( 'auto-draft' === $post->post_status || 'revision' === $post->post_type ) {
		return;
	}

	$shortcode_regex = get_shortcode_regex();
	$shortcode_data  = xxx_recursively_parse_nested_shortcodes( $shortcode_regex, $post->post_content );

	/**
	 * Allow other code to save data from shortcodes in post content whenever
	 * a post is created or updated.
	 *
	 * @param  array    $shortcode_data  The array of shortcode data in the post.
	 * @param  int      $post_id         The post ID being saved.
	 * @param  WP_Post  $post            The post object being saved.
	 */
	do_action( 'xxx_save_post_shortcodes', $shortcode_data, $post_id, $post );
}

/**
 * Return an array of all shortcodes in $content and their attributes.
 *
 * This function will recurse to handle nested shortcodes. There are several tricky
 * things about the logic here, and this is mostly a result of the way Core handles
 * shortcode parsing (see $matches after the preg_match_all() call, for example), but
 * the basic strategy is that we take a pass for each level of shortcode nesting and
 * build an array of all the shortcodes and their attributes at that level, then we
 * recurse as needed, passing along the array we're building, until we do a pass where
 * no shortcodes are detected, then we return our built array.
 *
 * For the structure of $matches, see /wp-includes/shortcodes.php.
 *
 * @param   string        $regex     The regex to match all shortcodes.
 * @param   string|array  $content   The array resulting from preg_match_all().
 * @param   array         $existing  The tracking array of existing matches.
 *
 * @return  array                    The complete array of nested shortcodes.
 */
function xxx_recursively_parse_nested_shortcodes( $regex, $content, $existing = array() ) {

	// Maybe concatenate $content values from previous matching,
	// and support $content being a string or an array.
	if ( is_array( $content ) ) {
		$content = implode( ' ', $content );
	}

	// Search for shortcodes.
	$count = preg_match_all( "/$regex/", $content, $matches );

	// If we have shortcodes, extract their attributes and maybe recurse,
	// otherwise return the shortcodes we've already found.
	if ( $count ) {

		// Loop over each attribute string, extract attributes, and save them
		// in an array keyed by the shortcode name.
		foreach ( $matches[3] as $index => $attributes ) {

			// Create a key for the shortcode name if we haven't already.
			if ( empty( $existing[ $matches[2][ $index ] ] ) ) {
				$existing[ $matches[2][ $index ] ] = array();
			}

			// Parse shortcode atts.
			$shortcode_data = shortcode_parse_atts( $attributes );

			// Save the found attributes under the key.
			$existing[ $matches[2][ $index ] ][] = $shortcode_data;
		}

		// Recurse as needed.
		return xxx_recursively_parse_nested_shortcodes( $regex, $matches[5], $existing );

	} else {

		return $existing;
	}
}

This is admittedly a function that takes time to fully grok. The key to making it work is the recursion. Since the WordPress Core shortcode regex only parses one level deep on each pass, we need to keep recursing on the strings of content between shortcode opening and closing tags until we take a pass where we don’t find any more shortcodes, then we return the array that we keep building with each pass.

Given the following content string:

[heading level="2"]Best Heading Ever[/heading][blockquote style="wide"]Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit diam, dignissim sodales hendrerit eget, dictum vel lorem.[/blockquote][button text="Visit Site" url="https://example.com" color="blue"][/button]

[product id="1234"][button text="Add to Cart" url="https://example.com/cart/add?id=1234" color="green"][/button][/product]

[product id="5678"][button text="Add to Cart" url="https://example.com/cart/add?id=5678" color="green"][/button][/product]

The shortcode data array looks like this:

Array
(
    [heading] => Array
        (
            [0] => Array
                (
                    [level] => 2
                )

        )

    [blockquote] => Array
        (
            [0] => Array
                (
                    [style] => wide
                )

        )

    [button] => Array
        (
            [0] => Array
                (
                    [text] => Visit Site
                    [url] => https://example.com
                    [color] => blue
                )

            [1] => Array
                (
                    [text] => Add to Cart
                    [url] => https://example.com/cart/add?id=1234
                    [color] => green
                )

            [2] => Array
                (
                    [text] => Add to Cart
                    [url] => https://example.com/cart/add?id=5678
                    [color] => green
                )

        )

    [product] => Array
        (
            [0] => Array
                (
                    [id] => 1234
                )

            [1] => Array
                (
                    [id] => 5678
                )

        )
)

Here’s an example of using this to save product ids from shortcodes like [product id="1234"]:

<?php

add_action( 'xxx_save_post_shortcodes', 'xxx_save_product_ids_in_shortcodes', 10, 3 );
/**
 * Save product ids from [product] shortcodes in meta whenever a post is saved.
 *
 * @param  array    $shortcode_data  The array of shortcode data in the post.
 * @param  int      $post_id         The post ID being saved.
 * @param  WP_Post  $post            The post object being saved.
 */
function xxx_products_save_product_ids( $shortcode_data, $post_id, $post ) {

	$product_ids = array();

	// If we have any [product] shortcodes, loop over each instance
	// of them and build our array of product ids.
	if ( array_key_exists( 'product', $shortcode_data ) ) {
		foreach ( $shortcode_data[ $product_shortcode ] as $shortcode_atts ) {
			if ( ! empty( $shortcode_atts['id'] ) ) {
				$product_ids[] = $shortcode_atts['id'];
			}
		}
	}

	// Filter out duplicates.
	$product_ids = array_unique( $product_ids );

	// Sanitize.
	$product_ids = array_map( 'sanitize_text_field', $product_ids );

	// If we found any product ids, save them, otherwise delete previous meta values.
	if ( ! empty( $product_ids ) ) {
		update_post_meta( $post_id, '_xxx_products_in_content', $product_ids );
	} else {
		delete_post_meta( $post_id, '_xxx_products_in_content' );
	}
}

You could always save the entire array of shortcode data under a single meta key, but I usually find that I want separate meta keys for specific shortcodes. The beauty of passing the shortcode data to an action hook is that any other code can hook in and save whatever meta key it wants, with no additional overhead from additional regex passes.

Bonus

Thinking more about the nested shortcodes use case, what if you want to also know the parent shortcode of a specific shortcode instance? Knowing this would let you manipulate a meta key only when a specific shortcode is inside another shortcode. This can be accomplished by making a slight tweak to the original function from above:

<?php

/**
 * Return an array of all shortcodes in $content, their attributes, and their parent shortcodes.
 *
 * @param   string        $regex        The regex to match all shortcodes.
 * @param   string|array  $content      The array resulting from preg_match_all().
 * @param   array         $existing     The tracking array of existing matches.
 * @param   array         $parent_tags  The parent shortcodes from a previous pass.
 *
 * @return  array                       The complete array of nested shortcodes.
 */
function xxx_recursively_parse_nested_shortcodes( $regex, $content, $existing = array(), $parent_tags = array() ) {

	// Maybe concatenate $content values from previous matching,
	// and support $content being a string or an array.
	if ( is_array( $content ) ) {
		$content = implode( ' ', $content );
	}

	// Search for shortcodes.
	$count = preg_match_all( "/$regex/", $content, $matches );

	// If we have shortcodes, extract their attributes and maybe recurse,
	// otherwise return the shortcodes we've already found.
	if ( $count ) {

		// Reindex the array of $parent_tags.
		$parent_tags = array_values( $parent_tags );

		// Loop over each attribute string, extract attributes, and save them
		// in an array keyed by the shortcode name.
		foreach ( $matches[3] as $index => $attributes ) {

			// Create a key for the shortcode name if we haven't already.
			if ( empty( $existing[ $matches[2][ $index ] ] ) ) {
				$existing[ $matches[2][ $index ] ] = array();
			}

			// Parse shortcode atts.
			$shortcode_data = shortcode_parse_atts( $attributes );

			// If the shortcode has a parent shortcode, add an attribute to
			// indicate this.
			if ( ! empty( $parent_tags[ $index ] ) ) {

				$parent_tag = array(
					'parent_shortcode' => $parent_tags[ $index ],
				);

				$shortcode_data = array_merge( $shortcode_data, $parent_tag );
			}

			// Save the found attributes under the key.
			$existing[ $matches[2][ $index ] ][] = $shortcode_data;
		}

		// Set up parent tag matching for the next pass by removing any matches
		// that don't have child shortcodes.
		foreach ( $matches[5] as $index => $parent_content ) {

			$child_count = preg_match_all( "/$regex/", $parent_content, $child_matches );

			if ( ! $child_count ) {
				unset( $matches[2][ $index ] );
				unset( $matches[5][ $index ] );
			}
		}

		// Recurse as needed.
		return xxx_recursively_parse_nested_shortcodes( $regex, $matches[5], $existing, $matches[2] );

	} else {

		return $existing;
	}
}

This does introduce one extra regex pass for each nesting level into the function, so if you don’t need to know the parent shortcodes the simpler version will be faster, but this totally works. In the shortcode data array you get a parent_shortcode attribute on each shortcode instance that will contain the parent shortcode, if there was one.

Here’s what the same content string from above looks like when run through this version of the extraction function:

Array
(
    [heading] => Array
        (
            [0] => Array
                (
                    [level] => 2
                )

        )

    [blockquote] => Array
        (
            [0] => Array
                (
                    [style] => wide
                )

        )

    [button] => Array
        (
            [0] => Array
                (
                    [text] => Visit Site
                    [url] => https://example.com
                    [color] => blue
                )

            [1] => Array
                (
                    [text] => Add to Cart
                    [url] => https://example.com/cart/add?id=1234
                    [color] => green
                    [parent_shortcode] => product
                )

            [2] => Array
                (
                    [text] => Add to Cart
                    [url] => https://example.com/cart/add?id=5678
                    [color] => green
                    [parent_shortcode] => product
                )

        )

    [product] => Array
        (
            [0] => Array
                (
                    [id] => 1234
                )

            [1] => Array
                (
                    [id] => 5678
                )

        )
)

Pretty neat. Now we can see that the second and third instances of the button shortcode are inside product shortcodes.

I’m now using this system to save all kinds of meta and then directly accessing shortcode data through meta on the sites that I build. So far it’s been much more satisfying than relying on regex parsing every time I need this data, and I’ve only scratched the surface of what is possible with this approach.

Alpha Color Picker Control for the WordPress Customizer

WordPress comes with a great js-driven color picker called Iris, and it’s easy to use anywhere in the WordPress admin, including in the Customizer via the WP_Customize_Color_Control class. Out of the box Iris only supports picking hex color values, but I’ve always thought it should have an opacity slider and support color values in RGBa also.

I went looking for a solution last year while developing a theme, and I stumbled across a long-running Github issue that is still open on the Iris repository. Several solutions had been offered there, but in my testing they were a little buggy and incomplete, so I decided to take the best from each of the solutions already offered and work towards a better solution.

I’ve been iterating on my solution ever since, and after many improvements and fixes, I’m finally ready to share it with the world.

Here’s what it looks like:

Right now it is available on Github as a drop in control class for the Customizer. I decided to focus on the Customizer for now since live previewing color changes is all the rage, but the pieces are all there to add support for using the Alpha Color Picker throughout the WordPress admin.

Update: I created a jQuery plugin version of the Alpha Color Picker that can be used anywhere in the WordPress admin.

Using the Alpha Color Picker in the Customizer is nearly identical to using the stock WP color picker, but some additional options are available:

add_action( 'customize_register', 'xxx_customize_register' );
function xxx_customize_register( $wp_customize ) {

    // Inlcude the Alpha Color Picker control file.
    require_once dirname( __FILE__ ) . '/alpha-color-picker/alpha-color-picker.php';

    // Alpha Color Picker setting.
    $wp_customize->add_setting(
        'alpha_color_setting',
        array(
            'default'    => 'rgba(209,0,55,0.7)',
            'type'       => 'theme_mod',
            'capability' => 'edit_theme_options',
            'transport'  => 'postMessage'
        )
    );

    // Alpha Color Picker control.
    $wp_customize->add_control(
        new Customize_Alpha_Color_Control(
            $wp_customize,
            'alpha_color_control',
            array(
                'label'        => __( 'Alpha Color Picker', 'xxx' ),
                'section'      => 'colors',
                'settings'     => 'alpha_color_setting',
                'show_opacity' => true, // Optional.
                'palette'      => array(
                    'rgb(150, 50, 220)',
                    'rgba(50,50,50,0.8)',
                    'rgba( 255, 255, 255, 0.2 )',
                    '#00CC99' // Mix of color types = no problem
                )
            )
        )
    );
}

You can pass additional options for show_opacity and palette. These are both optional. Setting show_opacity to false will hide the opacity number value on the slider handle, and palette can be set as true, false, or an array of colors in RGB, RGBa, hex, or any combination of these values. If palette is omitted or set to true then the standard WP color picker palette will be used, and if set as false then the palette will be not included in the color picker.

I spent time working out all of the usability issues that I found with other solutions. I reworked the slider, palette, and default color button interactions so that the opacity slider updates itself properly whenever a palette or the default color button is clicked. I added clickable zones on the right and left sides of the slider to make it easier to get to alpha values of 0 or 100 and reworked the slider positioning to keep the handle in the correct location relative the slider. I added an animated transition on the slider to give it a sense of play and made sure the transition worked in all situations (click and drag, tap and drag, swipe, and single click). I added the show_opacity option and created the method for specifying a palette via an array of colors (with mixed color types supported). Finally, I cleaned up the code to better match the WordPress coding standards, added inline documentation to help others understand the code, and tested it thoroughly to make sure it performed well on mobile and across all major browsers.

My implementation is certainly not the only solution for picking RGBa colors. The ultimate solution would integrate more deeply with Iris rather than build on top of it, and it would be nice to somehow generate a fallback for browsers that don’t support RGBa. If I can find the time I’d love to head in that direction and try to get a proper patch into Iris that could eventually make its way into WordPress core, but for now my solution has been working great for my purposes. I encourage anyone out there to do anything you’d like with it including using it in your own themes and plugins. Feedback and pull requests on Github are always welcome.

-Braad

Directional Shadow Hover Effect using CSS and jQuery

I wanted to make a hover effect that looked like the user’s cursor was a light source that was casting a directional shadow against some text. I’m sure there are fancier ways to do this, but by writing some CSS and jQuery I came up with this:

See the Pen Sequential Letter Animation Starter Pen by Braad Martin (@BraadMartin) on CodePen.0

It’s built with three main pieces. First, my span-letters.js script to wrap each letter of a string in a span with a class to indicate its position in the string. Then some jQuery to add a class to the wrapper indicating which letter is being hovered. Finally, a bunch of CSS to handle the text-shadows used to create the directional shadow.

I used the nesting power of Sass to keep everything DRY. Here’s the CSS for the center position:

#target.l5 {
  .sl1 {
    text-shadow: -8px 4px 8px #444444;
  }
  .sl2 {
    text-shadow: -6px 4px 8px #444444;
  }
  .sl3 {
    text-shadow: -4px 4px 8px #444444;
  }
  .sl4 {
    text-shadow: -2px 4px 8px #444444;
  }
  .sl5 {
    text-shadow: 0px 4px 8px #444444;
  }
  .sl6 {
    text-shadow: 2px 4px 8px #444444;
  }
  .sl7 {
    text-shadow: 4px 4px 8px #444444;
  }
  .sl8 {
    text-shadow: 6px 4px 8px #444444;
  }
  .sl9 {
    text-shadow: 8px 4px 8px #444444;
  }
}

The key is that each letter gets a more intense shadow the further away it is from the letter being hovered. A simple transition on the spans ties the whole thing together and gives it a sense of response as you quickly hover across the letters.

With the structure in place, it’s easy to create variations. I’ve always been a sucker for 3D text effects, so I had to try an inset shadow:

See the Pen Sequential Letter Animation Starter Pen by Braad Martin (@BraadMartin) on CodePen.0

The shadow was fun, but I still wasn’t getting that feeling of the light coming from the cursor and shining on the top of the letters. I decided to try adding a color change, and to make it flexible and achieve additional DRYness I created Sass mixins for each letter based on how far it was from the target letter:

See the Pen Sequential Letter Animation Starter Pen by Braad Martin (@BraadMartin) on CodePen.0

Not bad. I made the color change noticeably dramatic to illustrate the effect. A more subtle color change would definitely add some realism.

With the mixins in place I can easily add more CSS properties to each letter. My next move will be to add mixins for each letter based on the direction AND how far it is from the hovered letter, which will allow me to keep all the CSS properties including the text-shadows in a clean set of mixins. That will make it much easier to try out new ideas very quickly. Sass is a life saver in these kinds of situations.

-Braad

Sequential Letter Animations using CSS3 & jQuery

I think that my recent exploration of individual letter hover effects was always going to lead me down this path. Once I wrote the JS for sequentially applying a class to individual letters in a string with a flexible timer structure, the ideas just kept coming. It all starts with this:

See the Pen Sequential Letter Animation Starter Pen by Braad Martin (@BraadMartin) on CodePen.0

With that JS, designing the effect is as simple as setting this line of CSS:

.container span.active {
  /* Do something crazy */
}

Then you can change the timing of the effect simply by changing the variables in the JS:

duration = 400; // Set duration of the effect here
speed = 100; // Set animation speed through the letters here
infiniteLoop = false // Set whether animation should keep on triggering

There is a lot of potential here. I'm only starting to scratch the surface:

Example 1 - Rotating Letters

See the Pen Sequential Letter Animations - Rotating Letters by Braad Martin (@BraadMartin) on CodePen.0

Example 2 - Leaning Letters

See the Pen Sequential Letter Animations - Leaning Letters by Braad Martin (@BraadMartin) on CodePen.0

Example 3 - 3D Letters

See the Pen Sequential Letter Animations - 3D Letters by Braad Martin (@BraadMartin) on CodePen.0

Example 4 - Inset Letters

See the Pen Sequential Letter Animations - Inset Letters by Braad Martin (@BraadMartin) on CodePen.0

Too much fun!

-Braad

Individual Letter Hover Effects using CSS3 & jQuery

I've been playing around with the idea of applying CSS3 transforms and other effects to individual letters in a string, and I wanted a flexible way to do this that didn't involve any special markup from the content author.

After testing some ideas I settled on writing a small jQuery plugin to handle the task of wrapping each letter of a string in its own span. I call the plugin Span Letters, and it looks like this:

( function( $ ) {

    // Example usage: jQuery( '.selector' ).spanLetters();

    $.fn.spanLetters = function() {

        // Loop through each element on which this function has been called
        this.each( function() {   
          
            // Make an array with each letter of the string as a value
            var words = $( this ).text().split( '' );

            // Loop through the letters and wrap each one in a span
            for ( i = 0; i in words; i++ ) {
                words[i] = '<span class="sl' + (i + 1) + ' span-letter">' + words[i] + '</span>'
            };

            // Join our array of span-wrapped letters back into a string
            var text = words.join( '' );

            // Replace the original string with the new string
            $( this ).html( text );
        })
    }
}( jQuery ));

This will wrap each letter in a span and give the span a unique sequential class that we can use to apply our individual letter styling. Of course we can also use something like span:nth-child() instead of using the sequential classes. We can bring this to life with some CSS like this:

.container {
  font-family: verdana;
  font-weight: bold;
  text-shadow: -1px 0 0px #FFADDA, 0 1px 0px #F99ACD, -2px 1px 0px #FFADDA, -1px 2px 0px #F99ACD, -3px 2px 0px #FFADDA, -2px 3px 0px #F99ACD, -4px 3px 0px #FFADDA, -3px 4px 0px #F99ACD, -5px 4px 0px #FFADDA, -4px 5px 0px #F99ACD, -6px 5px 0px #FFADDA, -5px 6px 15px #000000;
  text-transform: uppercase;
}

.container span {
  display: inline-block;
  transition: 0.8s;
}

.container .sl1 {
  color: red;
  transform: rotateX( 20deg ) rotateY( -20deg ) rotateZ( 10deg );
}

.container .sl2 {
  color: orange;
  transform: rotateX( 0deg ) rotateY( 0deg ) rotateZ( -15deg );
}

.container .sl3 {
  color: yellow;
  transform: rotateX( 0deg ) rotateY( 30deg ) rotateZ( 25deg );
}

.container .sl4 {
  color: green;
  transform: rotateX( 0deg ) rotateY( 5deg ) rotateZ( -5deg );
}

.container .sl5 {
  color: blue;
  transform: rotateX( 20deg ) rotateY( 0deg ) rotateZ( -35deg );
}

.container .sl6 {
  color: indigo;
  transform: rotateX( 10deg ) rotateY( 0deg ) rotateZ( 5deg );
}

.container .sl7 {
  color: violet;
  transform: rotateX( 0deg ) rotateY( 30deg ) rotateZ( 35deg );
}

.container .sl8 {
  color: white;
  transform: rotateX( -10deg ) rotateY( 0deg ) rotateZ( -15deg );
}

.container .sl9 {
  color: black;
  transform: rotateX( -10deg ) rotateY( 0deg ) rotateZ( 15deg );
}

.container:hover span {
  transform: rotateX( 0deg ) rotateY( 0deg ) rotateZ( 0deg );
  cursor: pointer;
}

To create this:

Transform

Hover/Tap to revert to normal

That's pretty neat, but how can we make this more functional? I like the idea of transitioning into or out of the effect when the user hovers over the text. Here are some examples:

Example 1 - 2D Spinning Letters

.container {
  font-family: verdana;
  font-weight: bold;
  text-shadow: -1px 0 0px #FFADDA, 0 1px 0px #F99ACD, -2px 1px 0px #FFADDA, -1px 2px 0px #F99ACD, -3px 2px 0px #FFADDA, -2px 3px 0px #F99ACD, -4px 3px 0px #FFADDA, -3px 4px 0px #F99ACD, -5px 4px 0px #FFADDA, -4px 5px 0px #F99ACD, -6px 5px 0px #FFADDA, -5px 6px 15px #000000;
  text-transform: uppercase;
  color: white;
}

.container span {
  display: inline-block;
  transition: 0.8s;
}

.container:hover span:nth-child(odd) {
  transform: rotateX( 0deg ) rotateY( 0deg ) rotateZ( 370deg );
  cursor: pointer;
}

.container:hover span:nth-child(even) {
  transform: rotateX( 0deg ) rotateY( 0deg ) rotateZ( -370deg );
  cursor: pointer;
}
Result:

Transform

Hover/Tap for effect

Example 2 - 3D Spinning Letters

.container {
  font-family: verdana;
  font-weight: bold;
  text-shadow: -1px 0 0px #FFADDA, 0 1px 0px #F99ACD, -2px 1px 0px #FFADDA, -1px 2px 0px #F99ACD, -3px 2px 0px #FFADDA, -2px 3px 0px #F99ACD, -4px 3px 0px #FFADDA, -3px 4px 0px #F99ACD, -5px 4px 0px #FFADDA, -4px 5px 0px #F99ACD, -6px 5px 0px #FFADDA, -5px 6px 15px #000000;
  text-transform: uppercase;
  color: white;
}

.container span {
  display: inline-block;
  transition: 1.5s;
}

.container:hover span:nth-child(odd) {
  transform: rotateX( 0deg ) rotateY( 370deg ) rotateZ( 370deg );
  cursor: pointer;
}

.container:hover span:nth-child(even) {
  transform: rotateX( -370deg ) rotateY( 0deg ) rotateZ( -370deg );
  cursor: pointer;
}
Result:

Transform

Hover/Tap for effect

Example 3 - The Gangster Lean

.container {
  font-family: verdana;
  font-weight: bold;
  text-transform: uppercase;
  color: #545454;
}

.container span {
  display: inline-block;
  transition: 1s;
}

.container:hover span {
  transform: skewX( -10deg ) translateX( 10px );
  cursor: pointer;
}
Result:

Transform

Hover/Tap for effect

Example 4 - Individual Letter Scaling

.container {
  font-family: verdana;
  font-weight: bold;
  text-shadow: -1px 0 0px #FFADDA, 0 1px 0px #F99ACD, -2px 1px 0px #FFADDA, -1px 2px 0px #F99ACD, -3px 2px 0px #FFADDA, -2px 3px 0px #F99ACD, -4px 3px 0px #FFADDA, -3px 4px 0px #F99ACD, -5px 4px 0px #FFADDA, -4px 5px 0px #F99ACD, -6px 5px 0px #FFADDA, -5px 6px 15px #000000;
  text-transform: uppercase;
  color: white;
}

.container span {
  display: inline-block;
  transition: 0.8s;
}

.container:hover span {
  cursor: pointer;
  position: relative;
}

.container:hover .sl1 {
  transform: scale(1.25);
  z-index: 4;
}

.container:hover .sl2 {
  transform: scale(1.15);
  z-index: 3;
}

.container:hover .sl3 {
  transform: scale(1.05);
  z-index: 2;
}

.container:hover .sl4 {
  transform: scale(0.95);
  z-index: 1;
}

.container:hover .sl5 {
  transform: scale(0.85);
  z-index: 0;
}

.container:hover .sl6 {
  transform: scale(0.95);
  z-index: 1;
}

.container:hover .sl7 {
  transform: scale(1.05);
  z-index: 2;
}

.container:hover .sl8 {
  transform: scale(1.15);
  z-index: 3;
}

.container:hover .sl9 {
  transform: scale(1.25);
  z-index: 4;
}
Result:

Transform

Hover/Tap for effect

Example 5 - Text-Shadow Animations

.container {
  font-family: verdana;
  font-weight: bold;
  text-transform: uppercase;
  color: rgba(210, 210, 210, 0.6);
  text-shadow: 1px 2px 6px #FFFFFF, 0 0 0 #000000;
}

.container span {
  transition: 0.3s;
  display: inline-block;
}

.container:hover span {
  cursor: pointer;
  color: rgba(200, 200, 200, 0.6);
  text-shadow: 3px 6px 10px #FFFFFF, 0 0 0 #000000;
}
Result:

Transform

Hover/Tap for effect

With each letter wrapped in a span, the possibilities are endless.

-Braad

Hover zoom on image links using only CSS3 or only jQuery

I love CSS3. The new transforms are incredibly powerful, and I'm learning new things that I can do with them and the other new CSS3 features every day.

Here is a quick example of a CSS3 transform for image links that I've started using. The effect is a slow zoom on the image on hover. The markup requires a wrapper div and looks like this:

<div class="wrapper">
  <a href="#"><img src="someimage.jpg" alt="" /></a>
</div>

In our CSS we need to set a height or width on the wrapper div that is at least equal to the size of the image, along with overflow: hidden. Here we're using an image that is big, so it's safe to make it responsive by setting our wrapper width as a percentage and leaving height set to auto:

div.wrapper {
  overflow: hidden;
  width: 100%;
  height: auto;
}
a img {
  -webkit-transition: -webkit-transform 0.4s ease;
  -moz-transition: -moz-transform 0.4s ease;
  -o-transition: -o-transform 0.4s ease;
  transition: transform 0.4s ease;
}
a img:hover {
  -webkit-transform: scale(1.05);
  -moz-transform: scale(1.05);
  -ms-transform: scale(1.05);
  -o-transform: scale(1.05);
  transform: scale(1.05);
}

And the result:

kauai

This kind of effect is ideal when you've got big images that are fully rectangle or square shaped, which is why I love using it on photo galleries, portfolios, and big splash image backgrounds. It avoids re-sizing the element on the page but still adds that hint of interactivity that is key to making a website feel responsive to the user.

For added portability, you can use jQuery to apply the effect to all image links automatically. This can get tricky because the script needs to run after all images are loaded so that they have proper dimensions for it to measure to create the wrapper div, but it's a nice hack if the situation allows for it:

/* We are getting help here from desandro's imagesLoaded plugin, but this could be triggered differently to avoid this dependency */ 
$( document ).imagesLoaded( function() {

   // Select all images that are links
   var $imageLinks = $( 'a img' );
  
   // Loop through each image that is a link  
   $imageLinks.each( function(){

      // Store the current item
      var $this = $( this );

      // Wrap the image link in a div
      $this.parent( 'a' ).wrap( '<div class="img-link-wrapper" style="display: inline-block; text-align: center;"></div>' );

      // Setup initial css
      $this.css({ '-webkit-transition' : '0.4s ease',
                  '-moz-transition' : '0.4s ease',
                  '-o-transition' : '0.4s ease',
                  'transition' : '0.4s ease'
                });
     
      // Set the height of the wrapper div to the height of the image
      var imgHeight = $this.height();
      var imgWidth = $this.width();
      $this.parents( 'div.img-link-wrapper' )
           .css({ 'height' : imgHeight,
                  'width' : imgWidth,
                  'overflow' : 'hidden'
                });
   });

   // Set up a .hovered class
   $( 'body' ).append( '<style>.img-link-hovered {-webkit-transform: scale(1.05);-moz-transform: scale(1.05);-ms-transform: scale(1.05);-o-transform: scale(1.05);transform: scale(1.05);}</style>' );

   // add/remove the class on hover
   $( 'a img' ).hover(
      function() {
         $( this ).addClass( 'img-link-hovered' );
      }, function() {
         $( this ).removeClass( 'img-link-hovered' );
      }
   );
});

The result:

See the Pen Hover zoom on image links using only jQuery by Braad Martin (@BraadMartin) on CodePen.0

You might use a script like this to achieve the hover zoom effect in a situation where you're doing front-end work on top of some markup that you can't control. jQuery can be infinitely useful in these situations.

-Braad

Hover enlarge on image links using only CSS or only jQuery

I've grown fond of having images that are links grow in size when the user hovers over them with the mouse. My favorite way to achieve this effect uses only CSS and is rather simple. Say you have some html that looks like this:

<div class="wrapper">
  <a href="#"><img src="someimage.jpg" alt="" /></a>
</div>

We can achieve the effect by setting the height of the wrapper to the height of our image, which allows us to set the height of the image to something like 92% and set margin-top to 4% (half the difference between 92% and 100%). Then we take away the margin-top and set height to 100% on hover using the :hover pseudo-class.

For an image that is 250px by 250px, the CSS would look like this:

.wrapper {
  width: 250px;
  height: 250px;
  text-align: center;
}

.wrapper img {
  margin: 4% 0;
  height: 92%;
  width: auto;
}

.wrapper img:hover {
  margin: 0;
  height: 100%;
}
And the result:
gretsch-catalina-club-in-natural

Well that works great for square images and images that are taller than they are wide, but what about images that are short and wide? You can make it work with these images by setting the image to grow by its width rather than its height, and setting the initial margin on the left and right. This will cause the image to grow downwards from its initial position, but setting an initial margin-top and margin-bottom equal to half the number of pixels the image grows vertically by will keep it vertically centered. For this image that is 250px wide by 129px tall, the magic margin number is 5px:

.wrapper {
  width: 250px;
  height: 129px;
  text-align: center;
}

.wrapper img {
  margin: 5px 4%;
  width: 92%;
  height: auto;
}

.wrapper img:hover {
  margin: 0;
  width: 100%;
}

The result:

meinl-bongos

If you want to get real fancy, you can add a transition animation. If you add one on hover, make sure to add one on the way out for ultimate smoothness:

.wrapper {
  width: 250px;
  height: 250px;
  text-align: center;
}

.wrapper img {
  margin: 4% 0;
  height: 92%;
  width: auto;
  -webkit-transition: margin 0.3s, height 0.3s;
  -moz-transition: margin 0.3s, height 0.3s;
  -o-transition: margin 0.3s, height 0.3s;
  transition: margin 0.3s, height 0.3s;
}

.wrapper img:hover {
  margin: 0;
  height: 100%;
  -webkit-transition: margin 0.3s, height 0.3s;
  -moz-transition: margin 0.3s, height 0.3s;
  -o-transition: margin 0.3s, height 0.3s;
  transition: margin 0.3s, height 0.3s;
}
The result:
gretsch-catalina-club-in-natural

Once you start playing with transition timing functions and delays you can do some very cool effects, and if you bring in some box-shadow and filters the possibilities become endless.

This could also be wrapped up in some jQuery for added flexibility. There are a couple of extra things to think about, like whether you have any padding or margin already set on certain images that might be critical to the layout, but here is a quick example that will target all images that are links and doesn't require any markup changes:

// Start on window load because we need images to be loaded 
$( window ).load( function(){

   // Loop through each image that is a link
   $( 'a img' ).each( function(){

      // Store the current item
      var $this = $( this );

      // Wrap the image link in a div
      $this.parent().wrap( '<div class="img-link-wrapper" style="display: inline-block; text-align: center;"></div>' );

      // Set the height of the div to the height of the image
      var imgHeight = $this.height();
      var imgWidth = $this.width();
      $this.parents( 'div.img-link-wrapper' )
           .css({ 'height' : imgHeight,
                  'width' : imgWidth     
                });

      // Set the rest of the initial css
      $this.css({ 'height' : '94%',
                  'width' : 'auto',
                  'margin' : '3% 0'
                });
   });

   // Set up a .hovered class
   $( 'body' ).append( '<style>img.img-link-hovered{ margin-top: 0 !important; margin-bottom: 0 !important; height: 100% !important; }</style>' );

   // Add/remove the class on hover
   $( 'a img' ).hover(
      function() {
         $( this ).addClass( 'img-link-hovered' );
      }, function() {
         $( this ).removeClass( 'img-link-hovered' );
      }
   );
});

See the Pen Hover enlarge on images that are links by Braad Martin (@BraadMartin) on CodePen.0

What fun!

-Braad