death of a themer - frontend united - 14 april 2013
DESCRIPTION
"Death of a themer" was presented by James Panton and myself at Frontend United on 14th April 2013. This was a revised and extended talk of the same name presented by James at DrupalCamp London on 2nd March 2013. http://www.slideshare.net/therealmcjim/death-of-a-themer-drupal-camplondon2013 Themers are the magicians who transform what Drupal wants to do into what the designer wants it to do. They work alongside developers and site builders and are usually hammering out CSS files, overriding templates, writing theme functions and scratching their heads. The thing is — and whisper this if possible redundancy concerns you — we can bypass the themer entirely. With some simple configuration, a site builder can get Drupal to output exactly the semantic, lightweight markup that any modern front-end designer would be proud of. The designer can be left alone to write the most appropriate HTML, CSS and JS, while the site builder need only choose a couple of options when putting together content types, views and panels to make Drupal behave. A friendly developer may have to lend a hand every now and then, but that’s it. You can get rid of the themer altogether. This is an extended version of a session James did recently but will take a closer look at the tools and workflow we created and the design principles that initially drove us to this approach.TRANSCRIPT
Hello, we’re James and Matt
@mcjim and @MattFielding
from Code Enigma
developer
site builder
themer
designer
developer
site builder
themer
designer
developer
site builder
themer (deceased)
designer
the life of a themer
overworked
the life of a themer
overworked angry
the life of a themer
overworked angry frustrated
the life of a themer
overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff overriding stuff
hap
pin
ess
time
the theming curve
Murder Investigation
developer
site builder
designer
whodunnit?
the developer?
whodunnit?
“...to be honest, I never really saw the themer.We worked on different floors.”
official statement
the designer?
whodunnit?
excluded
15 columns, why? arrgghh $£@^£$%
“...there was a clash between my personal design principles and practices and his methods”
official statement
what did he mean bydesign principlesand practices?
Text
they are guides for the way we approach problems and craft our methods
design principles
here are 3 to start us off
minimise waste
waste is any activity where no value is produced
use the best tools
pick the tools that fit your workflow
PreprocessorsSass - CSS preprocessingLess - similar to SassStylus - a good but less popular preprocessorSusy/Singularity/ZenGrids/GridSet - grid system generatorsCompass - add-on functionality for Sass like vertical rhythm, sprites, css3 etcBourbon - Similar to Compass much to their dismayToolkit - A few nice extras to have - https://github.com/Snugug/toolkitCSS FrameworksSMACSS - styleguide/framework for developing css that is both modular and scalableOOCSS - object oriented CSS - more strict than smacssStyleguide generationKSS - uses comments in files to generate a styleguide - http://warpspire.com/posts/kss/Typecast - quick way to generate styles for typeClarify - http://www.clarify.ioStyle-Sites - https://github.com/snugug/style-sitesBrowsersChrome - Supports Sass in the web inspector - needs sass debugging turned on Canary - Same as above but also supports source mapsSafari - can use the desktop web inspector on the remote iphone/ipad site
Static page generatorsHammer for Mac http://hammerformac.com/Middleman - a bit more complex - requires command line http://middlemanapp.com/CodeKit - http://incident57.com/codekit/index.phpMixture.io http://mixture.io/Serve - Riby gem https://github.com/gummesson/serveTesting Live ReloadGuard - command line tool, faster than live-reloadAdobe Edge Inspect - http://html.adobe.com/edge/inspect/Mixture.io - http://mixture.io/Virtual Box with Windows XP and snapshots with IE6, IE7, IE8Lots of devicesTypographytypecast - http://typecast.com/ - can preview fastColourKuler - https://kuler.adobe.com/Colour Lovers - http://www.colourlovers.com/Color Scheme Designer - http://colorschemedesigner.com/http://color.hailpixel.com/Static image prototypingInvisionApp - very slick - http://invisionapp.com/Shipment - nice dropbox integration - http://blog.shipmentapp.com/
Browser ExtentionsWeb Inspector - needs sass debugging turned on and experimental modeSpeed TracerYSlowAdobe edge InspectLive ReloadVisual design and layoutFireworks - for working out Photoshop - mainly for image manipulationInDesign - some very useful tools for wireframesIllustrator - creating SVG files and illustrationsUXPin - http://uxpin.com/Useful websites and guidesHTML5 Please - http://html5please.com/Javascript Compression Tool - http://jscompress.comCompass - http://compass-style.org/examples/compass/HTML 5 Outliner - http://gsnedders.html5.org/outliner/Fontello - Icon Font generator - http://fontello.com/http://responsivepx.com/http://css3gen.com/button-generator/Sharing and experimenting with codeDabblet - http://dabblet.com/JS Fiddle - http://jsfiddle.net/CodePen - http://codepen.io/Practical tipsStart with pens and paper
add – don’t remove
only include what we want and need
Text
design principles are used as guides to inform the decisions we make as designers – primarily the
practices we use to design
design practices
work with real content
content strategy and modeling should come before design
get to code quickly
doing so also minimises a lot of waste
design a process for each job
each project is different, so designa unique process for each
what happens if we follow these design principles and
practices
static html
pure and honest
these principles and practices can be applied by any
designer/frontend developer
what problems doesthis cause us?
traditional Drupal workflow
traditional Drupal workflow
traditional Drupal workflow
angry viking god themerdrowning in a sea of divs
“...there was a clash between my personal design principles and practices and his methods”
official statement
Murder Investigation
the site builder?
whodunnit?
“...I always got on really well with the themer. Hadn’t seen him much since he went on holiday, though.”
official statement
so, what happened when the themer went on holiday?
designer, site-builder and developer were left to cope
without a themer
developer and site-builder came up with a plan…
they knew the designer was frustrated and wanted to try
new methods of working
so, they let the designerdo what he wanted…
…and figured out a way of getting Drupal to output that without the help of a themer
theming without a themer
STEP ONE
the designer builtprototypes in HTML
designer handedHTML, CSS and JS
over to the site builder
CSS and JS wasplaced in the theme*
*can be created there in the first place
HTML was used asa markup guide
theming without a themer
STEP TWO
the developer setone or two things upfor the site builder
required code
a basic theme
base theme?
<div id="page-wrapper"><div id="page">
<div id="header"><div class="section clearfix">
<?php if ($logo): ?> <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home" id="logo"> <img src="<?php print $logo; ?>" alt="<?php print t('Home'); ?>" /> </a> <?php endif; ?>
<?php if ($site_name || $site_slogan): ?> <div id="name-and-slogan"> <?php if ($site_name): ?> <?php if ($title): ?> <div id="site-name"><strong> <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a> </strong></div> <?php else: /* Use h1 when the content title is empty */ ?> <h1 id="site-name"> <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a> </h1> <?php endif; ?> <?php endif; ?>
<?php if ($site_slogan): ?> <div id="site-slogan"><?php print $site_slogan; ?></div> <?php endif; ?> </div> <!-- /#name-and-slogan --> <?php endif; ?>
<?php print render($page['header']); ?>
</div></div> <!-- /.section, /#header -->
<?php if ($main_menu || $secondary_menu): ?> <div id="navigation"><div class="section"> <?php print theme('links__system_main_menu', array('links' => $main_menu, 'attributes' => array('id' => 'main-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Main menu'))); ?> <?php print theme('links__system_secondary_menu', array('links' => $secondary_menu, 'attributes' => array('id' => 'secondary-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Secondary menu'))); ?> </div></div> <!-- /.section, /#navigation --> <?php endif; ?>
<?php if ($breadcrumb): ?> <div id="breadcrumb"><?php print $breadcrumb; ?></div> <?php endif; ?>
<?php print $messages; ?>
<div id="main-wrapper"><div id="main" class="clearfix">
<div id="content" class="column"><div class="section"> <?php if ($page['highlighted']): ?><div id="highlighted"><?php print render($page['highlighted']); ?></div><?php endif; ?> <a id="main-content"></a> <?php print render($title_prefix); ?> <?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?> <?php print render($title_suffix); ?> <?php if ($tabs): ?><div class="tabs"><?php print render($tabs); ?></div><?php endif; ?> <?php print render($page['help']); ?> <?php if ($action_links): ?><ul class="action-links"><?php print render($action_links); ?></ul><?php endif; ?> <?php print render($page['content']); ?> <?php print $feed_icons; ?> </div></div> <!-- /.section, /#content -->
<?php if ($page['sidebar_first']): ?> <div id="sidebar-first" class="column sidebar"><div class="section"> <?php print render($page['sidebar_first']); ?> </div></div> <!-- /.section, /#sidebar-first --> <?php endif; ?>
<?php if ($page['sidebar_second']): ?> <div id="sidebar-second" class="column sidebar"><div class="section"> <?php print render($page['sidebar_second']); ?> </div></div> <!-- /.section, /#sidebar-second --> <?php endif; ?>
</div></div> <!-- /#main, /#main-wrapper -->
<div id="footer"><div class="section"> <?php print render($page['footer']); ?> </div></div> <!-- /.section, /#footer -->
</div></div> <!-- /#page, /#page-wrapper -->
<div id="page-wrapper"><div id="page"><div id="header"><div class="section clearfix"><?php if ($logo): ?><a href="<?php print $front_page;
?>" title="<?php print t('Home'); ?>" rel="home" id="logo"><img src="<?php print $logo; ?>" alt="<?php print t('Home'); ?>" /></a><?php
endif; ?><?php if ($site_name || $site_slogan): ?><div id="name-and-slogan"><?php if ($site_name): ?><?php if ($title): ?><div id="site-
name"><strong><a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name;
?></span></a></strong></div><?php else: /* Use h1 when the content title is empty */ ?><h1 id="site-name"><a href="<?php print
$front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a></h1><?php endif; ?><?php
endif; ?><?php if ($site_slogan): ?><div id="site-slogan"><?php print $site_slogan; ?></div><?php endif; ?></div> <!-- /#name-and-slogan
--><?php endif; ?><?php print render($page['header']); ?></div></div> <!-- /.section, /#header --><?php if ($main_menu ||
$secondary_menu): ?><div id="navigation"><div class="section"><?php print theme('links__system_main_menu', array('links' => $main_menu,
'attributes' => array('id' => 'main-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Main menu'))); ?><?php print
theme('links__system_secondary_menu', array('links' => $secondary_menu, 'attributes' => array('id' => 'secondary-menu', 'class' =>
array('links', 'inline', 'clearfix')), 'heading' => t('Secondary menu'))); ?></div></div> <!-- /.section, /#navigation --><?php endif; ?
><?php if ($breadcrumb): ?><div id="breadcrumb"><?php print $breadcrumb; ?></div><?php endif; ?><?php print $messages; ?><div id="main-
wrapper"><div id="main" class="clearfix"><div id="content" class="column"><div class="section"><?php if ($page['highlighted']): ?><div
id="highlighted"><?php print render($page['highlighted']); ?></div><?php endif; ?><a id="main-content"></a><?php print
render($title_prefix); ?><?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?><?php print
render($title_suffix); ?><?php if ($tabs): ?><div class="tabs"><?php print render($tabs); ?></div><?php endif; ?><?php print
render($page['help']); ?><?php if ($action_links): ?><ul class="action-links"><?php print render($action_links); ?></ul><?php endif; ?><?
php print render($page['content']); ?><?php print $feed_icons; ?></div></div> <!-- /.section, /#content --><?php if
($page['sidebar_first']): ?><div id="sidebar-first" class="column sidebar"><div class="section"><?php print
render($page['sidebar_first']); ?></div></div> <!-- /.section, /#sidebar-first --><?php endif; ?><?php if ($page['sidebar_second']): ?
><div id="sidebar-second" class="column sidebar"><div class="section"><?php print render($page['sidebar_second']); ?></div></div>
<!-- /.section, /#sidebar-second --><?php endif; ?></div></div> <!-- /#main, /#main-wrapper --><div id="footer"><div class="section"><?php
print render($page['footer']); ?></div></div> <!-- /.section, /#footer --></div></div> <!-- /#page, /#page-wrapper -->
<?php
print $content;
<?php
print $content;
<div id="<?php print $block_html_id; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>> <?php print
render($title_prefix); ?><?php if ($block->subject): ?> <h2<?php print $title_attributes; ?>><?php print $block->subject ?></h2><?php
endif;?> <?php print render($title_suffix); ?> <div class="content"<?php print $content_attributes; ?>> <?php print $content ?>
</div></div><?php
print $content;
<?php
print $content;
<?php
print $content;
a panels layout or two
/** * Implements hook_ctools_plugin_api(). */function ce_panels_ctools_plugin_api($module, $api) { if ($module == 'panels' && $api == 'styles') { return array('version' => 2.0); } if ($module == 'page_manager' && $api == 'pages_default') { return array('version' => 1); } if ($module == "panels_mini" && $api == "panels_default") { return array("version" => "1"); }}
/** * Implements hook_ctools_plugin_directory() */function ce_panels_ctools_plugin_directory($module, $plugin) { if ($module == 'page_manager' || $module == 'panels' || $module == 'ctools') { return $plugin; }}
<?php/** * @file * Layout definition for Code Enigma one column layout. */
/** * Panel layout definition. */$plugin = array( 'title' => t('Code Enigma One Column'), 'category' => t('Code Enigma'), 'icon' => 'ce_one_column.png', 'theme' => 'ce_one_column', 'regions' => array( 'content' => t('Content'), ),);
<?php/** * @file * Layout template for Code Enigma one column layout. * * Regions: * - content */
if (isset($content['content'])) { print $content['content'];}
a method for turning off all supplied CSS and JS
/** * Implements hook_js_alter(). */function mytheme_js_alter(&$js) { if (user_is_anonymous()) { $path_to_theme = path_to_theme(); $allowed_js = array( 'settings', 'misc/jquery.js', 'sites/all/modules/contrib/google_analytics/googleanalytics.js', ); foreach ($js as $key => $script) { if (!is_numeric($key) && !in_array($key, $allowed_js) && strpos($key, $path_to_theme) === FALSE) { unset($js[$key]); } } }}
theming without a themer
STEP THREE
add a few modules
display suitesemantic views
panelspanels everywhere semantic panels*
*using a forked version atmhttp://drupal.org/sandbox/mcjim/1899120
display suite
control over fieldand node markup
<img width="120" height="289" alt="useful alt text, ta"
src="/files/my_image.jpg" />
<div class="field field-name-field-image field-type-image
field-label-hidden">
<div class="field-items">
<div class="field-item even">
<img width="120" height="289" alt="useful alt text, ta"
src="/files/my_image.jpg">
</div>
</div>
</div>
view modes
semantic views
panelspanels everywhere semantic panels
an interface for wrapping content with markup
CONTENT<MARKUP> </MARKUP>
CONTENT<MARKUP> </MARKUP>
doesn't panels addloads* of divs?
*seriously, loads
<?php/** * @file * Layout template for Code Enigma one column layout. * * Regions: * - content */
if (isset($content['content'])) { print $content['content'];}
what do we end up with?
a real example
some rules
never write a .tpl.php
never write a .tpl.phpunless you really have to
start by outputting no markup at all
add markup via the UI
think carefully about where you add your layout classes
use Features andzero-touch deployment
Murder Investigation
was it a team effort?
whodunnit?
whodunnit?
was it a team effort?
whodunnit?
project manager
the PM did it
what have we learnedfrom this sorry tale?
design driven
give higher priority to the frontend
let designers take advantage of the best tools to improve speed
and reduce waste
group design & frontend dev
team structure
traditional Drupal workflow
new Drupal workflow
new Drupal workflow
split team effort evenly in sprints – creates a closer
working relationship across team disciplines
open up opportunities for contractors from outside
of Drupal
consistency
remove a layer of complexity for
site builders
markup is managed in UI only
dictate
reverse traditional drupal working methods
take an uncompromising approach to your markup
don’t let Drupal tell you what it should be – you show it who’s
boss
thank you!
epilogue
what happened to the team?
the designer was happy
site builder had an easy life
sprints were productive
the themer SURVIVED and adopted a new identity as a frontend developer
which was a great fit for the team
there were trust issues with the PM so he moved on
the end
questions?
exit
@MattFielding@mcjim