Slide 1

Slide 1 text

*Beautiful Markup Curing DIV-itis with Semantic HTML, CSS and Presenters JOHN ATHAYDE, INFOETHER NOVARUG 29 JUN 2010

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

http://www.flickr.com/photos/frengo/992920521/

Slide 5

Slide 5 text

*Beautiful Markup Curing DIV-itis with Semantic HTML, CSS and [maybe] Presenters JOHN ATHAYDE, INFOETHER NOVARUG 29 JUN 2010

Slide 6

Slide 6 text

(or please stop killing baby animals with your HTML and CSS)

Slide 7

Slide 7 text

Let’s Assume... » YOU KNOW HTML & CSS BASICS » YOU KNOW RAILS » YOU WANT TO MAKE IT BETTER

Slide 8

Slide 8 text

STOP Please.

Slide 9

Slide 9 text

*Let’s Talk About... what the problem is in the fi rst place.

Slide 10

Slide 10 text

http://www.flickr.com/photos/toby_d1/3588461929/ Views are still... The Wild West

Slide 11

Slide 11 text

http://gist.github.com/78365
    <% playlist.listings.each_with_index do |listing, i| -%> <% if i < show %> <% composition = listing.composition %> <% position = i %>
  1. <%= position+1 %>
    <%#= link_to awesome_truncate(composition.title,30), label_release_track_path(composition.label.slug, composition.release.slug), :title => composition.title %>
    <%= link_to awesome_truncate(composition.title,30), composition_path(composition), :title => composition.title %>
    • Preview    <%= link_to_function(image_tag("icon_speaker_preview.png", :alt => "Preview", :title => "Preview"), "") %>
    • <% if !composition.member_contributed %>
    • <% if composition.network? %> <%= link_to image_tag("button_playlist_download.gif", :alt => "Download"), downloads_path(:audio_item_id => composition.audio_items.first.id), :method => :post%> <% else %> <%= link_to(image_tag("cart.gif", :alt => "Add to cart", :title => "Add to cart"), selections_path(:salable_id => composition.id, :salable_type => composition.class.name), :method => :post) %> <% end -%>
    • <% end -%>
    <%= linked_profiles(composition) %>
      <%= render :partial => "/ratings/rating_list", :locals => {:class_name => composition.class.superclass.name, :ratable => composition}%>
    • <%= link_to_function(image_tag("icon_load_in_player.png", :alt => "Add to Playlist",:title => "Add to Playlist"), "addCompositionToPlayerPlaylist(#{composition.id})" %>
  2. <% end %> <% end -%>
An example... a 60 line partial (called 30 times in one page)

Slide 12

Slide 12 text

    <% playlist.listings.each_with_index do |listing, i| -%> <% if i < show %> <% composition = listing.composition %> <% position = i %>
  1. <%= link_to awesome_truncate(composition.title,30), composition_path(composition), :title => composition.title %>

    <%= linked_profiles(composition) %>

      <%= render :partial => "/ratings/rating_list", :locals => {:class_name => composition.class.superclass.name, :ratable => composition}%>
    • <%= link_to_function(image_tag("icon_load_in_player.png", :alt => "Add to Playlist",:title => "Add to Playlist"), "addCompositionToPlayerPlaylist(#{composition.id})") %>
  2. <% end %> <% end -%>
A quick cleanup...

Slide 13

Slide 13 text

Do The Math. 60 LOC Partial* 30 = 1800 LOC 24 LOC Partial* 30 = 720 LOC (that’s a whole lotta books)

Slide 14

Slide 14 text

Didn’t even touch: * Helper methods * Presenters * Brazillian Jujitsu

Slide 15

Slide 15 text

(don’t use this)

Slide 16

Slide 16 text

#profile .left.column #date= print_date #address= current_user.address .right.column #email= current_user.email #bio= current_user.bio
<%= print_date %>
<%= current_user.address %>
<%= current_user.email %>
<%= current_user.bio %>
Bake Off! <%= ERB %>

Slide 17

Slide 17 text

#profile .left.column #date= print_date #address= current_user.address .right.column #email= current_user.email #bio= current_user.bio
<%= print_date %>
<%= current_user.address %>
<%= current_user.email %>
<%= current_user.bio %>
<%= ERB %> Bake Off!

Slide 18

Slide 18 text

DIV DIV DIV DIV IV DI (OMG.) DI

Slide 19

Slide 19 text

(oh yes, he went there.) IF YOU LIKED IT THEN YOU SHOULDA PUT A DIV ON IT DIV

Slide 20

Slide 20 text

(don’t use this) unless you know what you’re doing ^ Revision.

Slide 21

Slide 21 text

#profile .left.column %p #date= print_date %p #address= current_user.address .right.column %p #email= current_user.email %p #bio= current_user.bio

<%= print_date %>

<%= current_user.address %>

<%= current_user.email %>

<%= current_user.bio %> Have your cake... <%= ERB %>

Slide 22

Slide 22 text

*Don’t Hate haml The tool is not the problem...

Slide 23

Slide 23 text

The hand coders do it too... http://www.flickr.com/photos/scooter811/1475730494/

Slide 24

Slide 24 text

html { overflow-y: scroll; } What is this?!? There’re aren’t enough *(&*(#@)!% ...

Slide 25

Slide 25 text

Learn the elements They aren’t scary. html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td

Slide 26

Slide 26 text

http://www.smashingmagazine.com/2010/05/13/ css-2-1-and-css-3-help-cheat-sheets-pdf/ http://www.smashingmagazine.com/2009/07/06/ html-5-cheat-sheet-pdf/ Helping hands Cheat Sheets!

Slide 27

Slide 27 text

HIERARCHY Where it’s at.

Slide 28

Slide 28 text

This is a page headline.
This is a section head
This is body text and it goes on for miles and miles. I like cheese.
This is going to be a list of items:
- Item 1
- Item 2
- Item 3
No Hierarchy Not semantic, everything is the same.

Slide 29

Slide 29 text

No Hierarchy Not semantic, everything is the same.

Slide 30

Slide 30 text

This is a page headline.

This is a section head

This is body text and it goes on for miles and miles. I like cheese.

This is going to be a list of items:

  • Item 1
  • Item 2
  • Item 3
Semantic. HTML Tags used for meaning

Slide 31

Slide 31 text

Semantic. HTML Tags used for meaning

Slide 32

Slide 32 text

Declare DOCTYPE. And then develop to it HTML 4.01 Strict HTML 4.01 Transitional HTML 4.01 Frameset XHTML 1.0 Strict XHTML 1.0 Transitional XHTML 1.0 Frameset XHTML 1.1 HTML (5) MORE ABOUT DOCTYPES: www.alistapart.com/articles/doctype/

Slide 33

Slide 33 text

Validate Valid HTML Makes CSS Happy ONLINE: validator.w3.org

Slide 34

Slide 34 text

http://www.flickr.com/photos/roll_initiative/3278642272/ Generated Markup THIS ONE IS DANGEROUS

Slide 35

Slide 35 text

<%= div_for @product do %> <% end %> div_for? Don’t use this.

Slide 36

Slide 36 text

<%= content_tag_for(:li, @product, :class => "bar") %> <% end %> content_tag But only if you must...
  • li.product.bar {}
  • Slide 37

    Slide 37 text

    Use the elements! Lists are lists. Not divs with bullets. <% @unit.unit_client_scans.each do |client_scan| %>  • <%= client_scan.value %>
    <% end %>
      <% @unit.unit_client_scans.each do |client_scan| %>
    • <%= client_scan.value %>
    • <% end %>

    Slide 38

    Slide 38 text

    Could be cleaner Write html.
      <% @product.each do |product| %>
    • <% end %>
    • ...
    ul.products {} ul.products li {} ul.products li.bar {}

    Slide 39

    Slide 39 text

    Helpers Avoid Markup def full_name(person) “

    #{@person.first_name} #{@person.last_name}

    ” end def full_name “#{@person.first_name} #{@person.last_name}” end

    Slide 40

    Slide 40 text

    Helpers Summarization is where they shine. def referrer_for(account) if account.referrer referral = “Referred_by #{account.referrer.name}” if account.web_contact? “#{referral} via Web registration” else referral end else “Web registration” end end

    Slide 41

    Slide 41 text

    HTML IS CODE Stop having code generate code.

    Slide 42

    Slide 42 text

    Zen Coding Use a tool, not a generator div#page>img.logo+ul#navigation>li*5>a
    PROJECT FILES: code.google.com/p/zen-coding/

    Slide 43

    Slide 43 text

    *Why it matters Not all user agents are created equal...

    Slide 44

    Slide 44 text

    WEB ACCESSIBILITY Take care of your users

    Slide 45

    Slide 45 text

    Google is a blind user. http://www.flickr.com/photos/scooter811/1475730494/

    Slide 46

    Slide 46 text

    §508 www.section508.gov

    Slide 47

    Slide 47 text

    START SMALL Cover the basics all the time. WAI Level 1 Checklist: www.w3.org/TR/WCAG10/full-checklist.html

    Slide 48

    Slide 48 text

    Web Accessibility ERB Examples link_to @product.name, product_path(@product), :title => “Take a look at #{@product.name}” image_tag “product_12758.png”, :alt => “#{@product.name}” link_to (image_tag “product_12758.png”, :alt => “#{@product.name}”), product_path(@product), :title => “Take a look at #{@product.name}”

    Slide 49

    Slide 49 text

    Web Accessibility = Well Formed HTML Not just an afterthought.

    Slide 50

    Slide 50 text

    *Enhance! And not like in the movies...

    Slide 51

    Slide 51 text

    PROGRESSIVE enhancement Add features for those who can use them

    Slide 52

    Slide 52 text

    No content

    Slide 53

    Slide 53 text

    No content

    Slide 54

    Slide 54 text

    Write it once Let the backend fi gure out the browser switches GET ecsstender: www.ecsstender.org

    Slide 55

    Slide 55 text

    HTML 5 Dive on in LEARN IT: www.diveintohtml5.org * Geolocation * Canvas * Video * New input types * Local databases

    Slide 56

    Slide 56 text

    Modernizr. Javascript to the rescue! .multiplebgs div p { /* properties for browsers that support multiple backgrounds */ } .no-multiplebgs div p { /* optional fallback properties for browsers that don't */ } GET modernizr: www.modernizr.com

    Slide 57

    Slide 57 text

    *Legacy issues... from all those classic UI hacks!

    Slide 58

    Slide 58 text

    <%= content %>
    Rounded Corners. http://frst.in/~lX Seriously.

    Slide 59

    Slide 59 text

    Rounded Corners.
    <%= content %>
    “CSS3” The Beast. .box-to-be-rounded { border: 1px solid #ccc; border-radius: 5px; /* IE9, Opera 10.5 */ -webkit-border-radius: 5px; /* Safari, Chrome */ -moz-border-radius: 5px; /* Firefox */ }

    Slide 60

    Slide 60 text

    <%= f.label :first_name %> *
    <%= f.text_field :first_name %> Required Fields Love the form you’re with. span.required {color: red;}

    Slide 61

    Slide 61 text

    Required Fields <%= f.label :first_name, :class => “required” %> <%= f.text_field :first_name %> Progressively enhance! label { display: block; } label.required { color: red; } label.required:after { content: “*”; } REFERENCE: www.quirksmode.org/css/beforeafter.html Not supported in MSIE 7 and below, 8 does not accept images for content

    Slide 62

    Slide 62 text

    http://nanobox.chipx86.com/blog/2006/07/before-and-after-in-ie7-and-below.php Required Fields Hackety hacked for MSIE 7 [code redacted to protect the children]

    Slide 63

    Slide 63 text

    *Presenting... Let’s get down to the sexy: Rails Presenters

    Slide 64

    Slide 64 text

    Encapsulation. http://www.flickr.com/photos/shuffle-art/2810247509/

    Slide 65

    Slide 65 text

    Generic Reuse. http://www.flickr.com/photos/chokingsun/3495110670/

    Slide 66

    Slide 66 text

    Present it. http://www.flickr.com/photos/_zahira_/4579176204/

    Slide 67

    Slide 67 text

    REFERENCE: blog.jayfields.com/2007/03/rails-presenter-pattern.html Present it.

    Slide 68

    Slide 68 text

    REFERENCE: blog.jayfields.com/2007/03/rails-presenter-pattern.html Present it. class OrderController < ApplicationController def complete @presenter = CompletePresenter.new(params[:presenter]) redirect_to thank_you_url if request.post? && @presenter.save end def thank_you end end

    Slide 69

    Slide 69 text

    REFERENCE: blog.jayfields.com/2007/03/rails-presenter-pattern.html Present it. class CompletePresenter < Presenter def_delegators :user_account, :name, :name= def_delegators :address, :line_1, :line_2, :city, :state, :zip_code :line_1=, :line_2=, :city=, :state=, :zip_code= def_delegators :user_credentials, :username, :password, :username=, :password= def user_account @user_account ||= UserAccount.new end def address @address ||= Address.new end def user_credentials @credentials ||= UserCredential.new end def save user_account.save && address.save && user_credentials.save end end

    Slide 70

    Slide 70 text

    *CSS Tricks... The good, bad and ugly of CSS Templates and Dynamic CSS

    Slide 71

    Slide 71 text

    Dynamic CSS http://www.flickr.com/photos/shinez/4004798080/

    Slide 72

    Slide 72 text

    Why Generate? There are a few justi fi ed cases * You are supporting themes * You have an insanely large CSS set * You have an app that you redeploy to many clients (aka, theming)

    Slide 73

    Slide 73 text

    Get SASSy Haml back again !darkgrey = #221f10 #sidebar background-color: !darkgrey #sidebar { background-color: #221f10; } generates... Get LESS: www.lesscss.org

    Slide 74

    Slide 74 text

    {less} is more Variable Driven CSS @brand_color: #4D926F; #header { color: @brand_color; } h2 { color: @brand_color; } Get LESS: www.lesscss.org

    Slide 75

    Slide 75 text

    {less} is more Variable Driven CSS #header { color: red; a { font-weight: bold; text-decoration: none; } } #header {color: red;} #header a { font-weight: bold; text-decoration: none; } Get LESS: www.lesscss.org

    Slide 76

    Slide 76 text

    {less} is more Variable Driven CSS @the-border: 1px; @base-color: #111; #header { color: @base-color * 3; border-left: @the-border; border-right: @the-border * 2; } #footer { color: (@base-color + #111) * 1.5; } Get LESS: www.lesscss.org

    Slide 77

    Slide 77 text

    sprites http://www.flickr.com/photos/gettysgirl/3481084323/ Sprites.

    Slide 78

    Slide 78 text

    Not Very Fairy reduce the server calls for icons/images BACKGROUND: www.alistapart.com/articles/sprites

    Slide 79

    Slide 79 text

    DETAILS: 37signals.com/svn/posts/2336-using-css-sprites-with-rails-helper-methods Sprites in Helpers Classic like... <%= image_tag ("email.gif"), :class => "email" %> <%= image_sprite :email, :class => "email", :title => "Email" %>

    Slide 80

    Slide 80 text

    def image_sprite(image, options = {}) sprites = { :add_icon => {:w => 16, :h => 16, :x => 0, :y => 0}, :email => {:w => 26, :h => 16, :x => 41, :y => 0}, :print => {:w => 25, :h => 17, :x => 68, :y => 0}, :trash => {:w => 10, :h => 11, :x => 94, :y => 0}, :comments => {:w => 13, :h => 13, :x => 105, :y => 0}, :comments_read => {:w => 13, :h => 13, :x => 120, :y => 0}, :comments_unread => {:w => 13, :h => 13, :x => 135, :y => 0}, :rss => {:w => 14, :h => 14, :x => 150, :y => 0}, :ical => {:w => 14, :h => 16, :x => 166, :y => 0}, :drag => {:w => 11, :h => 11, :x => 360, :y => 0}, :timeclock => {:w => 17, :h => 17, :x => 375, :y => 0}, :timeclock_off => {:w => 17, :h => 17, :x => 392, :y => 0} } %(#{options[:title]}) end DETAILS: 37signals.com/svn/posts/2336-using-css-sprites-with-rails-helper-methods

    Slide 81

    Slide 81 text

    css template (bad) CSS Templates http://www.flickr.com/photos/owaters/3846053408/

    Slide 82

    Slide 82 text

    Why? Derived from the print world... http://www.flickr.com/photos/eadaoinflynn/3666328306/

    Slide 83

    Slide 83 text

    http://www.flickr.com/photos/bashford/4330125086/

    Slide 84

    Slide 84 text

    .container_12 .grid_1{ width:60px; } .container_12 .grid_2{ width:140px; } .container_12 .grid_3{ width:220px; } .container_12 .grid_4{ width:300px; } .container_12 .grid_5{ width:380px; } .container_12 .grid_6{ width:460px; } 960.gs Not Semantic

    Slide 85

    Slide 85 text

    X Survey says...

    Slide 86

    Slide 86 text

    Toupee. http://www.flickr.com/photos/eadaoinflynn/3666328306/

    Slide 87

    Slide 87 text

    LAYERED APPROACH Turn it on and o f REFERENCE: github.com/marchdoe/toupee

    Slide 88

    Slide 88 text

    Build Your Own Framework http://www.flickr.com/photos/dystopos/315312589/

    Slide 89

    Slide 89 text

    *Quick Starts... Saving time with a gem generator to get up and running with a basic setup

    Slide 90

    Slide 90 text

    ONE FILE to bring them all and on the server bind them. Put that in your pipe and smoke it!

    Slide 91

    Slide 91 text

    Calling All CSS /* Title: Screen styles and MSIE patches Author: John Athayde */ /* import stylesheets and hide from IE/Mac \*/ @import url("reset.css") screen; @import url("master.css") screen; @import url("print.css") print; /* Plugin stylesheets */ @import url("../javascripts/jquery-ui-1.8.1/css/cupertino/jquery-ui-1.8.1.custom.css") screen; /* If there are any styles that we want IE5/Mac to see, we put them after this */ Classic like... <%= APP_CONFIG[:name] %> <%= stylesheet_link_tag 'application.css', :media => 'screen, projector' %> app/layouts/application.html.erb public/stylesheets/application.css

    Slide 92

    Slide 92 text

    My Base App Setup Rails 3 app w/CSS, Javascript, MSIE hacks, etc. * MSIE 6/7 Speci fi c styles * MSIE 24 bit PNG fi xes * Clear fi x * Custom Gems (Deadweight/Startups) CSS STARTUP: www.github.com/boboroshi/infoether-framework

    Slide 93

    Slide 93 text

    A more robust method that covers javascript too... JAMMIT INFO: documentcloud.github.com/jammit “Jammit is an industrial strength asset packaging library for Rails, providing both the CSS and JavaScript concatenation and compression that you'd expect, as well as YUI Compressor and Closure Compiler compatibility, ahead-of-time gzipping, built-in JavaScript template support, and optional Data-URI / MHTML image and font embedding.”

    Slide 94

    Slide 94 text

    startups http://www.flickr.com/photos/dierken/948171048 STARTUPS GEM: www.github.com/infoether/startups

    Slide 95

    Slide 95 text

    *Clean up that mess Code audits, unused CSS and moving to production

    Slide 96

    Slide 96 text

    Organize it! Standardize what you do as a team. input, textarea { border-radius: 3px; /* IE9, Opera 10.5 */ -webkit-border-radius: 3px; /* Safari, Chrome */ -moz-border-radius: 3px; /* Firefox */ font-size: 1.4em; padding: 5px; } Alphabetical, with vendor speci fi c switches kept next to o ff i cial attributes.

    Slide 97

    Slide 97 text

    Write Shorthand Combine those things together! input { border-width: 1px; border-color: #fff; border-style: solid; } input { border: 1px solid #fff; }

    Slide 98

    Slide 98 text

    Unused Selectors UI side: Dust Me Selectors FIREFOX ADD-ON: www.sitepoint.com/dustmeselectors

    Slide 99

    Slide 99 text

    Unused Selectors Gem: Deadweight GEM REPOSITORY: www.github.com/aanand/deadweight # lib/tasks/deadweight.rake require 'deadweight' Deadweight::RakeTask.new do |dw| dw.mechanize = true dw.root = 'http://staging.example.com' dw.stylesheets = %w( /stylesheets/style.css ) dw.pages = %w( / /page/1 /about ) dw.pages << proc { fetch('/login') form = agent.page.forms.first form.username = 'username' form.password = 'password' agent.submit(form) fetch('/secret-page') } dw.ignore_selectors = /hover|lightbox|superimposed_kittens/ end

    Slide 100

    Slide 100 text

    http://www.flickr.com/photos/cheeseroc/2202100903/ TESTS Don’t write tests around markup if you don’t have to.

    Slide 101

    Slide 101 text

    TIDY Because rendered code is always slightly messy. http://www.flickr.com/photos/muehlinghaus/3564021462/

    Slide 102

    Slide 102 text

    Final delivery... Rack::Tidy sudo gem install rack-tidy # above Rails::Initializer block require 'rack/tidy' # inside Rails::Initializer block config.middleware.use Rack::Tidy config/environment.rb Rack::Tidy Info: coderack.org/users/webficient/middlewares/38-racktidy TIDY Info: www.w3.org/People/Raggett/tidy/ tidy.sourceforge.net/docs/quickref.html

    Slide 103

    Slide 103 text

    http://www.flickr.com/photos/chadmiller/145648847/ Do it for the cute baby animals.

    Slide 104

    Slide 104 text

    Q&A Fire when ready.

    Slide 105

    Slide 105 text

    * SLIDES: www.boboroshi.com (soon!) THANKS! CSS STARTUP: www.github.com/boboroshi/infoether-framework STARTUPS GEM: www.github.com/infoether/startups TWITTER: @boboroshi