Drupal

A better way to theme Field Collections

Field collections are at the same time one of my most favorite and least favorite aspects of working with Drupal 7. Since they are entities they can be extremely powerful and flexible site building tools, and I see lots of unrealized potential in that, on the other hand theming can be tricky and, for lack of better word, generally feels “icky.” There is little documentation online about best practices with almost all links pointing back to this thread on how to theme field collections. The proposed solutions in this thread are a mixed bag — mostly bad — but some that may work, but they certianly don’t follow any best practices in drupal theming. I’ll admit I have shipped field collection theming that, while working, did make me feel “dirty.” Below was a clean solution that — while simple — is maintainable and, hopefully easy to follow.

I created a quick function that pulled out the themed items from the field collection and organized them into an easy to theme array. The theming then felt a lot more natural, like working with a views rows template.

<?php
/**
 * Creates a simple text rows array from a field collections, to be used in a
 * field_preprocess function.
 *
 * @param $vars
 *   An array of variables to pass to the theme template.
 *
 * @param $field_name
 *   The name of the field being altered.
 *
 * @param $field_array
 *   Array of fields to be turned into rows in the field collection.
 */
 
function rows_from_field_collection(&$vars, $field_name, $field_array) {
  $vars['rows'] = array();
  foreach($vars['element']['#items'] as $key => $item) {
    $entity_id = $item['value'];
    $entity = field_collection_item_load($entity_id);
    $wrapper = entity_metadata_wrapper('field_collection_item', $entity);
    $row = array();
    foreach($field_array as $field){
      $row[$field] = $wrapper->$field->value();
    }
    $vars['rows'][] = $row;
  }
 }
}

In this function we pull in the “variables” array from the field template, the field name and an array of fields that we want to extract, and then load them into our own rows array which gets attached to the variables array for use in our template. It uses the entity_metadata_wrapper that is like a swiss army knife of sanity and clean code for Drupal 7. If you aren’t familar with it, start with this documentation page about entity metadata wrappers, and follow up with some quick googling. It’ll make you and your code happy.

Below is the function being called and our custom field template being established. One thing that keeps our code simple is that all fields in the field collection are required eliminating the need to check for the variables existence in the template.

<?php
function THEME_preprocess_field(&$vars, $hook){
  if ($vars['element']['#field_name'] == 'field_achievements') {
    $vars['theme_hook_suggestions'][] = 'field__achievements_collected';
 
    $field_array = array('field_award', 'field_award_presenter','field_year');
    rows_from_field_collection($vars, 'field_achievements', $field_array);
  }
}

Finally below is the field template.

<?php
/**
 *  Field formatter for the field_achievements field collection.
 */
?>
<dl>
  <?php foreach($rows as $row): ?>
    <dt><?php print $row['field_award']; ?></dt>
    <dd><?php print $row['field_award_presenter']; ?></dd>
    <dd><?php print $row['field_year']; ?></dd>
  <?php endforeach; ?>
</dl>

We had a number of fields that were just sets of text data that needed to be output in definition lists. The function could be easily modifed to render the fields instead of just the values by using entity_view(). Next steps for this approach would be to refactor to use entity info to get the fields so that it can be generic and would no longer require the need to pass in the fields that you want.

There is hope for theming within the module itself. There is a promising issue in the queue that looks like it makes the native theming more sane. Since it’s such a big change it doesn’t look likely that it’ll make it into the 1.0 branch, so we may need to wait for the next version before it drops. Perhaps there is space for an add-on contrib module that cleans up the theming.

Magic: Frontend Performance for all themes

Howdy perfers!

This week’s Webperf Wednesday is short and sweet, just like your page loads when you install this new module that enhances any Drupal theme. Magic is a set of frontend performance and development workflow tools for themers. Previously many themes had their own advanced settings — many of which did the same things as other themes, but they all did it a little differently — no more with Magic.

Built by Web Chef Ian Carrico and Sam Richard (of Aurora) with contributions from Sebastian Siemssen (of Omega), Magic was built by the desire to work together to make all themes better, instead of siloing improvements within specific themes.

What’s inside?

Performance features:

  • Enhancements to CSS Aggregation
  • Exclude CSS files from being included
  • Option to move JavaScript to the footer
  • Backport of Drupal 8 JavaScript handling
  • Exclude JS files from being included

Development goodies

  • Rebuild Theme Registry on Page Reload
  • Display a Viewport Width indicator
  • Display an indicator with classes applied to the HTML. Useful when used in conjunction with Modernizr
  • Export theme settings

That last one is super important, as it makes Drupal themes a little more DRY. With Magic, you can take your settings from one theme to another — or to another site completely — because they’re fully exportable. Have two different projects, and want similar asset output despite one being Omega and one being Zen? No problem, just export!

Note: the full import process has yet to land, but it’s coming very soon.

If you have an awesome trick that you always rely on during theming, open an issue and propose it to Magic. They’d love to hear from you.

Give it a shot today! Go to drupal.org/project/magic

DrupalCon Portland: Mobile Roundup

DrupalCon is coming! In just a little over a month, our Drupal community will meet in Portland to learn what’s new in the web and Drupal. I have already begun checking out the schedule to find some of the best frontend talks.

Sessions

Sam Richard (@snugug) and Mason Wendell (@codingdesigner) are giving a talk on how to develop a responsive site with Sass and Breakpoint. I have had the pleasure of working with both of these guys with the work for Team Sass, and look forward to their session about the changes with Breakpoint.

Josh Riggs (@joshriggs) will be showing the Zen of HTML Prototyping and Designing in the Browser. This is especially important for ensuring the proper mobile design is ready for the client. We have been designing within the browser over the past year at Four Kitchens and are excited to see what other companies have been doing with it.

Vadim Mirgorod (@dealancer) has a session to Integrate Backbone.js into Drupal 7 and 8. We have already begun to use Backbone.js to create some awesome mobile and responsive apps at Four Kitchens, and I am exited to learn new ways to integrate it into a Drupal site.

Jared Ponchot (@jponch) of Lullabot will have a session about Designing for the responsive age we live in. I look forward to seeing some tips and tricks I can apply to our design process here at Four Kitchens, and possibly better ways of thinking of responsive design.

Training

Want to start DrupalCon off running, and get a full-day responsive training? Chris Ruppel, Sam Richard and I are offering Advanced Responsive Web Design with Sass + Compass on May 20th. This shouldn’t be missed for anybody who wants to learn about how to properly implement a responsive design, and the tools to use to make your life easier.

One less JPG

I’d like to demo a simple how-to. There are many, many techniques to make pages load faster, but this post attempts to demonstrate large gains from very small code changes.

People often build beautiful sites with multiple easy-to-use JavaScript libraries. Then, when it comes to addressing frontend performance, suddenly those libraries are an enormous download that the users are forced to bear.

Just one image

Before you go worrying about how to minify every last library or shave tests out of Modernizr, try and see if you can remove just one photo from your design. It will make a bigger difference.

Coined by Adam Sontag, the “one less JPG” idea — nay, MOVEMENT — is summed up perfectly here:

Real example

Last year we re-launched Pressflow.org. We have some mobile traffic, but it’s likely people just browsing for info, since no one has a good reason to download Pressflow onto a phone or tablet. Let’s keep their attention and make the experience fast.

We have this huge, beautiful mountain on the homepage. It’s great. But it’s also 160K. I tried making it smaller, or splitting the photo off of the background pattern, but it decreased the quality of the photo too much when I lowered the file size. We made a wonderfully small SVG logo, but that’s not an option for a photograph with this kind of detail.

How much impact does it have?

A mountain is a big thing — just like the amount of traffic Pressflow can handle — and the image we chose was meant to convey that vastness. Since it doesn’t really pack the same punch on smaller screens, why include it at all? I decided to use Modernizr and conditionally load the stylesheet that references the mountain. That way it never gets loaded by tiny screens that don’t need it.

Using the Modernizr Drupal module, I added a conditional load into the .info file of my theme:

; Load CSS with Modernizr
modernizr[Modernizr.mq('screen and (min-width: 42em)')][yep][] = css/big.css

This tells Modernizr to output a Modernizr.load() statement with the test I specified. In this case, Modernizr will only load big.css if the test is true. My test checks the width of the window using a media query — .mq() — and returns true if the screen is at least 42em, causing the CSS to be fetched. Here’s the JavaScript output:

Modernizr.load({
  test: Modernizr.mq('screen and (min-width: 42em)'),
  yep : 'http://pressflow.org/sites/all/themes/pfo/css/big.css',
});

So that’s it, instant savings!

..oh what’s that? Always test your work? Thanks for keeping me honest.

Here’s some data.

I’ve got two network waterfalls here for comparison. They show a pretty stark difference following this one-line change to my code. If a screen isn’t big enough for the mountain, it’ll only take 20 HTTP requests and 193K total. If the screen is big enough, it takes 24 HTTP requests — for the CSS and then the images inside it — totalling 384KB total. That’s a savings of 191KB (almost exactly 50%) from a single change to my code. You’d have to remove 19 copies of jQuery 2.0 to achieve this kind of bandwidth savings.

(by the way, didja hear that jQuery 2.0 has small QSA-only custom builds?)

Small screens

Waterfall: Conditional load small

Big screens

Waterfall: Conditional load big

You can see in the second waterfall that the Initiator of big.css is modernizr.min.js, meaning that JavaScript loaded the file after running the test.

ThoughtContentLoaded

I hope this shows how easy it can be to reduce your page weight without worrying about shaving bytes of JavaScript that are supplying valuable functionality if you know how to use them right.

If you want to know more about the conditional loading API within Modernizr, head over to yepnope.js documentation and start reading. For more Drupal-specific examples check out the official documentation for conditional loading using the Modernizr module.

DrupalCamp Austin: Past, Present, and Future

From its inception in 2009, Four Kitchens has been heavily involved in the planning and organizing of DrupalCamp Austin, along with other Austin Drupal leaders like Astonish Design, Volacci, and Entermedia (to name a few).

It seemed like in 2011, we had hit our stride: Angela Byron was keynoting, we produced one of the first responsive DrupalCamp websites, introduced full-day training to the camp, and finally found a cool Druplicon mascot (we love you, hipster Druplicon).

Then in 2012, things came to a halt. Maybe the Mayans meant to predict the end of DrupalCamp Austin and not the end of the world. Okay, maybe not. But 2012 was definitely a turning point in the Austin event landscape with the inaugurating Formula 1 race at Circuit of the Americas. While CoA is great for the Austin economy, it was bad news for us and our camp.

Every hotel in Austin and the metro area was booked solid for the whole month of November, which is when we usually host our camp. We didn’t want to put on a camp that would be inaccessible to folks from out of town, especially our friends in Dallas and Houston; so we decided to cancel the camp as a result. (Although we did have an awesome one-day event aptly called Drupal Day Austin.)

Back with a vengeance

We’re no Die Hard 3, but we are back with a vengeance in 2013! (Sam Jackson may even make an appearance at this year’s camp. Okay, no. Don’t get your hopes up.)

Here’s what’s new this year:

  • 3 days instead of 2: The camp will start on Friday with full-day trainings and a one-day web leadership summit open to anyone who works in the web (and free to attend!).
  • Full-day trainings take place on Friday so you can enjoy 2 days of camp, uninterrupted.
  • Half-day trainings will still be available the Saturday of the camp for those who prefer half-day training, and don’t mind missing half a day of camp talks.
  • Tech trivia Friday! Start off the camp with a fun trivia night and test your overall geeky knowledge.
  • We’re downtown, baby! Our venue this year is the Austin Convention Center, conveniently located right by the metro rail and near watering holes like Easy Tiger and The Gingerman (the unofficial post-meetup spot in Austin).

And now for the fun part!

Register for the camp

Submit a session

Get involved

Volunteer: Email us at volunteer (at) drupalcampaustin.org and let us know what you’re interested in.
Sponsor: Email me personally at cecy (at) fourkitchens.com to talk about sponsorship opportunities.
Train: Get in touch with Diana Dupuis at Astonish Design if you have any ideas or questions about training.

Stay updated

The best way to stay up-to-date is to follow @DrupalATX on Twitter or Facebook.

We hope to see you there!


Photo credit: jenniferconley on Flickr.

DrupalCon Portland Proposals Galore

I hope you’re ready to put a bird on it and pickle that, because DrupalCon Portland is coming!

We submitted a whole lot of sessions this year on a huge variety of topics, from frontend to backend. Here are the Web Chef proposed sessions for DrupalCon Portland. If any of these strikes your fancy, please feel free to leave a comment and make your voice heard.

Frontend

Coding + Development

Government, Nonprofit, and Education

Business and Strategy


Photo credit: Mr. Thomas on Flickr.

Minified JavaScript, on the Fly!

As web applications become richer and more complicated the amount of JavaScript running them increases. More code means longer download times which means more waiting before your application or web site is usable. Thankfully there’s an easy solution that’s already widely used in the web development community: minification. Minified JavaScript strips whitespace and renames variables to produce a smaller download size.

Removing whitespace is pretty straightforward, but renaming variables is a more abstract concept. With tools like UglifyJS this is handled for you but here’s an example of what’s going on. Let’s look at this simple function that takes a parameter and alerts a message with that variable:

var sayHi = function(name) {
  alert('Hi ' + name + '!');
};

With script minification the above code will be changed to this:

var sayHi=function(a){alert("Hi "+a+"!")};

without altering the behavior of the function. As you can see, all whitespace that can be removed has been and the variable “name” was changed to “a”. The end result is the removal of 26 characters from the code. It’s not hard to see that the savings from minification will quickly add up!

You can take this one step further by wrapping your code in immediately-invoked function expressions (IIFEs). That’s a pretty scary looking name, but chances are you’ve seen these before, this is an example:

(function($) {
  $('h1').css('text-decoration', 'blink');
}(jQuery));

The function wrapped in parentheses is immediately invoked with jQuery as its argument. Within the function jQuery is accessed with the $ variable. Abstracting variables in IIFEs is not required though, consider this case:

(function(Drupal) {
  Drupal.behaviors.sayHi = {
    attach: function(name) {
      alert('Hi ' + name + '!');
    }
  };
}(Drupal));

Minifying this code produces the following:

(function(a){a.behaviors.sayHi={attach:function(a){alert("Hi "+a+"!")}}})(Drupal);

Keeping the “Drupal” variable in your script makes sense because that’s the namespace you’re used to accessing it with and it does have meaning in the code, but by including it as an argument to the IIFE UglifyJS will replace any instances of “Drupal” with a shortened variable.

What about Drupal?

So, this is pretty cool, right? Unfortunately Drupal 7 doesn’t provide minification out of the box. Thankfully, there are contrib solutions to this problem! The Speedy module provides pre-minified scripts but unfortunately needs to be re-released every time core is updated or you need to re-minify the files yourself on core updates.

I wasn’t completely satisfied with this approach so I built uglify.me and a companion Drupal module, UglifyJS, to do script minification on the fly. uglify.me isn’t the only “minifier-as-a-service” out there, but I wanted to be able to throw something up quickly and be fairly confident that it wouldn’t upset some other poor developer out there hosting their own service.

The uglify.me service accepts POST requests of un-minified JavaScript and returns the minified version. Simple! The UglifyJS module provides an API to expose Drupal scripts that should be minified:

/**
 * Implements hook_uglifyjs_info().
 */
function mymodule_uglifyjs_info() {
  return array(
    drupal_get_path('module', 'mymodule') . '/js/mymodule.js',
  );
}

The downside to this approach is that each script will create another request to the uglify.me service when the site cache is cold. If you expose a lot of scripts to the UglifyJS API this will be time consuming and could cause timeouts.

If you’re running Pressflow 7.20.1+ or apply this patch to core and you have JavaScript concatenation enabled (which you should, if you’re in production) the UglifyJS module will automatically minify the concatenated scripts. This greatly reduces the number of requests to the web service and overhead associated with minification.

Caveats

The biggest issue that I’ve encountered with this module is the requests made to the external web service. If there’s a problem connecting to the remote server the time spent waiting for the response is wasted and can cause timeouts on cold caches. This is mitigated if you’re using Pressflow 7.20.1+ since core will not request files to be rebuilt if the hash of the concatenated scripts did not change.

The uglify.me service also currently strips some header comments from scripts which would could remove any copyright or license information if they exist. This should be fixable from the uglify.me service, so if it’s bothering you and I haven’t had time to fix it before you need it, As of uglify.me v0.1.0 any comment containing the words “license” or “copyright” (case insensitive), or the common build tags “@preserve” and “@cc_on” will not be stripped from the source code. This is controlled by a regular expression so if you find a general case that’s not met by the current regular expression open a pull request to fix it!

Conclusion

Script minification is a great way to reduce your site’s download footprint and increase usability. If bandwidth and performance are concerns you should be minifying, regardless of your ultimate solution. Informal testing on the recently released Full Plate Living site showed reduction in the front page’s download weight by an average of 110KB*. Not monumental, but not too bad either.

Happy minifying!

* Note: The UglifyJS module is not currently in use on the production Full Plate Living site, but it likely will be soon!

LMSs and more: Drupal in Education

At Four Kitchens, we have done quite a bit of work within the education industry. As we began looking into expanding our footprint within the education web technology space, we discovered that there was a corresponding need in the marketplace waiting to be filled; especially within higher ed. Universities and higher ed institutions continue to look for ways to cut costs, deliver content more effectively and easily, ease administration, and facilitate online learning/training. While several (open source and proprietary) solutions exist, there seems to be little clarity into what the options are, and perhaps more importantly, what the possibilities may be.

So we set out on a quest to understand the “lay of the land” a little better. Broadly speaking, there are three categories of solutions:

Learning Management Systems (LMS)

Succinctly, an LMS is a software application for the administration, documentation, tracking, reporting, and delivery of education courses or training programs. There are an incredible number of LMSs available to choose from; some proprietary, some open source, some completely custom built, some entirely off the shelf. Traditionally, LMSs have focused more on content delivery than content management, which is part of the reason we found that almost no academic institution is entirely happy with the LMS they chose to implement. Said another way, a complete solution for an academic institution involves the best aspects of CMS and LMS, and traditional LMSs have been very poor at CMS functionality.

Part of the problem, I venture to guess, is that there is surprisingly little available documentation around what the business and functional requirements of a good LMS are! The argument could be made that every academic institution has different needs and it is thus difficult to compile a unified set of requirements. But despite those differences, is there core functionality that we can distill as universally applicable? It would seem that at a minimum, the requirements of an LMS are:

  1. Classroom management (attendance, etc)
  2. Delivering content to students
  3. Collecting completed assignments
  4. Reporting student performance
  5. Streamlining administration
  6. Improve customer service
  7. Developing and queueing standard content, and providing opportunities to tailor content
  8. Provide self-service learning for students and employees
  9. Deploying learning resources and programs quickly
  10. Extending, maintaining, and enhancing communities

Some of the LMSs that we feel best meet these objectives are:

Canvas: Arguably the most robust and full featured LMS offering currently available, Canvas is on a meteoric rise and has been gaining use in both the higher ed and K-12 segments. It is an open source and open API product, and is one of the few LMSs that has a free mobile app to go along with it.

Sakai: Sakai is a full featured LMS built by many universities including University of Michigan, Indiana University, and Stanford, which has been adopted by several universities across the country. It is not open sourced, but operated on a community backed license. Corrected information: It has a very permissive open source license.

Moodle: Moodle is a fully featured and powerful LMS, but the once dynamic open source community behind it has seen some attrition. The LMS isn’t on the leading edge anymore, but with continued support from developers, it continues to remain very relevant.

ELMS: Headed by Bryan Ollendyke of Penn State University, ELMS is the most prominent Drupal based LMS. A lot of progress has been made, but there is still some work to be done, and Bryan is a well of knowledge on the subject and is happy to talk to anyone that wants to help further its development.

Blackboard: The original dominant LMS, Blackboard has been falling out of favor with the emergence and popularity of open source solutions. Through acquiring Moodle and Angel, and continued development, Blackboard still has a full feature set, as well as a mobile app.

While perhaps biased, Instructure (the makers of Canvas) have a feature comparison chart on their website.
Update 03/18/2013: The above line was removed because the feature comparison on Instructure’s website is not accurate.

Site building solutions and tools

Site building tools are especially important to higher ed institutions, as they frequently need to provide academic units and departments an easy way to brand themselves under the institution’s overall brand. ImageX Media, Chapter 3, Funny Monkey, and several others have done excellent work to provide open source solutions that provide the ability to manage content, rapidly deploy sites, control branding, etc. Our four favorite Drupal based solutions are:

Social based “LMS” platforms

This class of solutions is centered around giving teachers and students a way to interact easily online. It shifts away from the “heft” of traditional LMSs to try to facilitates easy communication, discussions, sophisticated learning opportunities (traditional and e-learning), content distribution/sharing, etc. Taking the view that allowing educators and students to connect more easily provides the greatest value, all the other functionality and bells and whistles are built around that core premise. While none of these services use Drupal, the big players are:

Edmodo: With 7.4 million users at over 80,000 schools, Edmodo is considered one of the best solutions for Elementary and Middle Schools. It boasts very good security safeguards and granular permissions controls, a high degree of personalization, and customers speak highly of the responsive support team. Edmodo was the first of its kind, but is now seeing increased competition from the next two in this list.

Lore (Coursekit): Lore is at the newcomer to this arena, but is moving to the forefront rather quickly thanks to strong financial backers. It is “Course-centric”, in that each course has it’s own private “social network”. Users love its clean and elegant UI.

Schoology: Schoology combines some of the best elements of Lore and Edmodo. One of the big selling points is that unlike Edmodo’s “wall” which can get cluttered. Schoology has threaded discussion boards to make content easier to find. It also has better security and permissions granularity controls than Lore. Despite the lite/social nature of the service, Schoology bills itself as being able to perform full-blown LMS functions.

What to choose?

With all these options out there (and these are truly just a sliver of the pantheon of offerings), it is easy for education institutions to feel completely overwhelmed by the choices available. Perhaps this is natural given our open source leanings at Four Kitchens, but we believe that the best option for education institutions is the one that makes data exchange, interoperability, and connected systems most easy to achieve. The process efficiencies, cost savings, ease of administration, reporting that higher ed and K-12 institutions crave can only be realized when the systems work in concert. A comment made by one educator that I talked to should be of particular note to technical service providers; he said, “All these educational services and websites try to be software and lock you in. What I would REALLY like is for a way to make all these systems talk to each other. If you can do that, you’ve got a real winner!”

Responsive Images: a Drupal Implementation

The popularity of responsive web design is constantly exposing behaviors that web browsers have gotten away with over the years. Many of these behaviors — while brilliant for a single-screen web — become a direct hindrance when dealing with the multi-screen extravaganza that we face now.

One of the most hotly debated topics is responsive images. This was a topic widely exposed by Filament Group due to their work on the Boston Globe, and it continues to be an issue for every bandwidth-conscious site today.

History

The foundations of this topic have been hotly debated and oft explored in the past year, so here’s a list of articles that capture the history of responsive images and demonstrate the challenges developers face on a modern site:

  • Mat Marquis, part of Filament Group and the Boston Globe team, took it upon himself to take the helm of this issue, writing about the initial challenges and creating the Responsive Images Community Group. The group has proposed a solution and is busy solidifying a web standard for responsive images, backed by the trial and error of developers worldwide.
  • Jason Grigsby has written extensively about responsive image techniques, deftly balancing the need for simplicity on the authors’ side, while recognizing the underlying tech issues browsers inadvertently (and rightfully) created during our beloved single-screen golden era.
  • Robert Paul Lloyd writes about how no solution is ideal, suggesting that we go back to the drawing board and create an entirely new image format. In the long term this is pretty likely. For certain types of imagery a bandwidth-cheap, scalable format already exists in SVG, icon fonts, and other vector formats. A similar vessel needs to exist for photos too.

Today’s solution

Whatever the final outcome of the standards process, if you find yourself needing responsive images today there are several approaches, the most successful of which is currently the <picture> element.

In a nutshell, <picture> is a brand new element with behavior that is — for now — controlled by JavaScript. This allows us to achieve all of the goals for a proper responsive image request: avoiding image prefetching, preferring author-controlled image selection, and ultimately only downloading a single image (instead of a fallback plus larger version)

Picturefill is its own open-source library, available on Github.

Implementing responsive images on a Drupal site

The latest responsive site that Four Kitchens launched, Full Plate Living, tightly integrates responsive images with Drupal content. The methods for doing so are thankfully rather easy, but as with all things Drupal there is a bit of a learning curve to get started. Responsive images can be added to content, views, etc. with the help of two contributed modules: Breakpoints and Picture. These two modules rely on Drupal’s core Image Styles module to output images in various sizes using a URL-specific, render-on-demand system.

Configuring breakpoints

In responsive web design breakpoints are used with media queries to determine when new CSS rules should apply to the site’s markup. As its name suggests, the Breakpoints module allows your site to define media queries on which you’d like to take action. The module provides a canonical list of breakpoints that are accessible from the database and thus surfaced to your site’s code. The Breakpoints module also has the notion of a “breakpoints group.” Groups are particularly useful for defining sets of breakpoints that are only relevant to certain parts of the site. These breakpoints can then be semantically referenced by their group name which allows you to reuse breakpoint names between groups, even if the media queries aren’t the same.

In the case of Full Plate Living we had one global set of breakpoints that was defined in the theme’s .info file:

breakpoints[smartphone] = (min-width: 320px)
breakpoints[fourhundred] = (min-width: 415px)
breakpoints[smartphone_only] = (min-width: 320px) and (max-width: 767px)
breakpoints[smartphone_landscape] = (min-width: 480px)
breakpoints[smartphone_landscape_only] = (min-width: 480px) and (max-width: 767px)
breakpoints[small_menu] = (min-width: 430px)
breakpoints[smaller_menu] = (min-width: 421px)
breakpoints[recipes_landing] = (min-wdith: 520px)
breakpoints[user_reg] = (min-width: 625px)
breakpoints[tablet] = (min-width: 768px)
breakpoints[tablet_only] = (min-width: 768px) and (max-width: 979px)
breakpoints[desktop] = (min-width: 980px)

This same set of breakpoints was used in our Sass and JavaScript files (with response.js) to provide a consistent list of breakpoints for all of our front end code to interact with. Unfortunately this list was duplicated in the three places; a future implementation might use a build tool like grunt to keep the global breakpoints list in one place and update the .info, Sass, and JavaScript definitions appropriately.

Additional breakpoint groups were added for content types so that the amount of markup required for responsive images could be kept down (one breakpoint means two picture options: the default, and the one defined for the breakpoint).

Configuring image styles

Core’s Image Styles are used to format the images that will be used in the picture element. It’s a good idea to give the image styles meaningful names so that configuring the Picture module is more straightforward. In the case of Full Plate Living we generally used two image styles per page: STYLE__full for images delivered to large viewports, and STYLE__mobile for images delivered to small viewports.

Configuring Picture

The Picture module ties information from Breakpoints and Image Styles together and ultimately provides the markup and picturefill JavaScript that will be used on the page. Each breakpoint group will have a tab on the Picture admin page that lists its breakpoints and provides a dropdown for each one to specify the image style that should be used.

Configuration UI for breakpoints within Picture module

Finally, when you’re defining the display style for your image fields you will choose “Picture” as the formatter for the image. The settings for this field will allow you to choose the “picture group” and a “fallback” image style. The fallback image style will be used if no breakpoint conditions are met. If you’re building mobile-first, this would be your base mobile style definition and should be the smallest image that will be delivered to the client.

Configuration UI for Picture image formatter

Show me the data

To demonstrate the advantages of the <picture> element we captured data from the Full Plate Living recipe landing page. See those beautiful, gigantic images below the search? Such a huge image is not needed for the same effect on a small screen. Implementing <picture> resulted in a difference of 157K out of a max page weight of 746K. Here are the two network waterfalls:

Mobile

Network waterfall for Full Plate Living taken from a small screen. The statistic of interest is a set of three content images whose default state causes their file sizes to be 15, 15, and 10 kilobytes.

The three images in this screenshot that start with 2012 are the mobile-formatted images. They total approximately 40K at the default breakpoint.

Desktop

Network waterfall for Full Plate Living taken from a laptop. The statistic of interest is a set of three content images whose JavaScript-altered state causes their file sizes to be 74, 47, and 76 kilobytes.

Looking again at those images with the same 2012 prefix, we see a total of 197K, meaning we are preventing the site from serving mobile users with approximately 157K of data that they don’t need.

You can see that the download “initiator” for the images is a script — not the HTML page — due to the picturefill script modifying the DOM and specifying the image that should be used. This DOM modification causes the markup on the page to differ based on the viewport, visible in this gist.

Div + data-attributes

The <picture> element was used on Full Plate Living, but for now it’s considered slightly more future-proof to use <div> elements with data attributes.

<div data-picture data-alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
    <div data-src="small.jpg"></div>
    <div data-src="medium.jpg"     data-media="(min-width: 400px)"></div>
    <div data-src="large.jpg"      data-media="(min-width: 800px)"></div>
    <div data-src="extralarge.jpg" data-media="(min-width: 1000px)"></div>
 
    <!-- Fallback content for non-JS browsers. Same img src as the initial, unqualified source element. -->
    <noscript>
        <img src="external/imgs/small.jpg" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
    </noscript>
</div>

The picturefill script and Picture module both currently use the <div> method, so although your markup will look different, the end result will be the same.

In conclusion

We all recognize the need for a responsive image container on the web. Today’s solution might look very different from tomorrow’s, but the need for device-optimized media will continue to grow as fast as the variety of devices accessing the web. Just hang on, remember to test, and enjoy the ride!

Credits: this article was co-written by Elliott Foster.

Inlining one-use JavaScript

Everyone does it.

There’s a piece of JavaScript that will only be used on one page, perhaps to provide some unique interactivity. It’s probably attached to a View or maybe a unique node ID. It’s so easy to toss in a drupal_add_js() and move on — or worse, throw the code in your theme. Wouldn’t it be nice if you could inline all these one-use scripts and make them appear only the page they’re needed?

Inline on the Fly

Here’s an easy way to inline scripts without losing the ability to edit them easily. We don’t want our code sitting in a PHP string so we create and maintain a real JS file, and use file_get_contents() to grab it whenever the appropriate page is built.

  // Ensure this JS ends up inline at the bottom of the page
  $options = array(
    'scope' => 'footer',
    'type' => 'inline',
  );
 
  // JS lives in its own file but is included inline when page renders
  $js_code = file_get_contents(drupal_get_path('module','my_module').'/my_code.js');
 
  // Add JS to page
  drupal_add_js($js_code, $options);

Optimized pages + organized code

I often find myself using hook_views_post_build() to apply this behavior when a specific Views display needs some custom JS to function properly. That way I don’t have to worry about the path, it just works anytime this View is used.

Avid Features users know it’s much more maintainable to keep the JS in its own file next to the View instead of stuffing it in a Views footer, or worse: tossing vital code for components into the theme’s “main” (read: only) JS file. Putting code in a theme file can seem swell until you copy a Feature for use in another project and just can’t figure out where that JavaScript went.

/**
 * Implements hook_views_post_build().
 */
function my_feature_views_post_build(&$view) {
  $has_run = &drupal_static(__FUNCTION__);
 
  if (!$has_run) {
    switch ($view->name) {
      // Check for the relevant View(s)
      case 'my_view':
        // Check for the relevant display(s)
        if ($view->current_display == 'my_block') {
          // Ensure this JS ends up inline at the bottom of the page
          $options = array(
          'scope' => 'footer',
          'type' => 'inline',
          );
 
          // JS lives in its own file but is included inline when page renders
          $js_code = file_get_contents(drupal_get_path('module','my_feature').'/my_code.js');
 
          // Add JS to page
          drupal_add_js($js_code, $options);
          $has_run = TRUE;
        }
        break;
    }
  }
}

Performance

Inlining a script avoids an http request and is great for frontend performance. However, if you have a page that is uncached and hit continuously, adding disk reads won’t be so great for the actual server’s performance. You can see in the second example there’s a reference to drupal_static(). This is a good way to avoid running a slow Drupal hook more than once per page request. Always make sure to cache the outcome of functions like this one in order to avoid too many disk reads.

Pages