Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker
Ward Penney

When Should I Build a Live Style Guide?

Ward Penney
Monday, June 3, 2013

Over the last several projects, we have chosen to commit to the construction and maintenance of a live style guide as part of the development process. However, the reasons in each case have been varied, and I’d like to give a quick rundown of these cases with some benefits and pitfalls of each.

My primary reasons to build an live style guide are when:

  • On a new codebase,

  • Bringing an existing frontend codebase under control, and

  • Implementing a “phase II” design.

Stipulations

  1. It must be a web-based product. I am unaware of any successful process for an live style guide on iOS, Android or any technology not using CSS and HTML.

  2. The live style guide must exist on a basic page that the developers and designers can affect quickly with HTML (preferring HAML, SLIM, etc), CSS (preferring SASS or LESS) and inline Javascript.

Universal Goals of a Live Style Guide

This is a good point to describe the goals for a live style guide. In all situations, my primary goals for using are:

  1. to showcase and create best practices for the team to use going forward,

  2. to properly factor the frontend codebase so future changes are straightforward and decoupled from each other, and

  3. to enable all members of the team to pair on it’s creation, maintenance and evolution.

Universal Benefits of a Live Style Guide

There are some general benefits that the live style guide brings, regardless of the context:

  • It creates a culture that appropriately estimates the scope of new widgets: I personally believe that CSS work is habitually under-estimated by agile teams and designers. New widgets, variance in widgets, conditional behavior, conditional display, and new layouts all increase the entropy of your frontend by a factor that is exacerbated over time. In the same way that adding a feature increases your codebase and maintenance costs, so do new design elements.

  • Eliminate handoffs by pairing with a visual designer: If the team has a visual human resource, pair with him or her as you build. If you don’t have a visual resource, bring in the product owner as you near completion of each bit. Most visual designers nowadays are interested and skilled in frontend development. Anecdotally, every designer I have paired with quickly recognized the advantage of repetition and versatility of widget design and then promptly eliminated unnecessary visual variance from their existing and future designs.

  • Spread best practices by pairing with engineering: It’s amazing how a little CSS best practices, mixed with pairing and with a dash of SASS-magic can transform all team members into competent and exceptional frontend developers. After all, agile engineering is no stranger to pairing. Arrange the pair assignments so the two of you hammer out a complex CSS design. They will appreciate it!

Situation 1: A New Codebase

Honestly, designing in-browser live style guide on a new codebase is one of the most exhilarating experiences us frontend geeks can find. The benefits in this context are:

New Codebase Benefits

  • Agile live style guide construction: Only put what you need for the upcoming iteration(s) into the LSG. If you only need H1 and H2, do not bother with H3, H4 and H5. If you only need one button, design that button (and make it POP!). You need a fancy table? Focus on that. Odds are that what you NEED ASAP is a manageable workload.

  • Make live style guide stories unpointed Chores: Resist acceptance process for the style guide. The consumer user does not see the live style guide. It will be accepted anyway down the line. Why subject it to double jeopardy  Any issue that might hold up the acceptance of the Feature when implemented, can be 90% handled during the live style guide phase by bringing over the designer or product owner and pointing at it on the screen.

New Codebase Pitfalls

  • Engineering catches up: This is in the pitfalls section only because you have to watch out for it and react appropriately. You can not create a bottleneck here. You know they caught up when they are picking Features off the backlog that have a corresponding story to style in the live style guide. This is time to delete your Chore for the style-only. By this time, you should have many elements in place, most notably a file include structure, a framework choice and at least one layout example. Do the style guide in the layout of the app. This way, you set the best practices for grid usage. Your goal is to enable the team so you can roll off, not create a bottleneck that requires you to create every line of CSS.

Situation 2: Bring an existing codebase under control

To be continued… 

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Stephan Hagemann

Showing and hiding conditional HTML without Javascript

Stephan Hagemann
Tuesday, May 21, 2013

Have you ever filled out an address form that had a checkbox for “my shipping address differs from my mailing address”? When you click that box a conditional form part gets revealed that allows you to enter another address. We had to build something very similar the other day and stumbled on a neat way to make the conditional part show and hide with CSS only.
Continue reading →

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ward Penney

Structure your SASS files with @import

Ward Penney
Monday, April 1, 2013

For my first blog post at Pivotal, I decided to pick a small topic that I am pretty confident about: why to structure your SASS files with the @import rule.

If you are still using Sprockets directives in Asset Pipeline to combine your SASS files, I highly recommend to switching over to using the SASS @import rule instead.

Consider this simple CSS setup:

application.css (using Sprockets Directives)

/*
 *= require partials/variables
 *= require partials/typography
 *= require partials/elements

 *= require vendor/grid
 *= require vendor/mixins

 *= require pages/home
 *= require pages/listing
 *= require pages/detail
 */
(NOTE: I am intentionally not using "*= require_tree" right now.)

The same setup using SASS @import rule would look like this:

application.sass (using SASS @import)

@import partials/variables
@import partials/typography
@import partials/elements

@import vendor/grid
@import vendor/mixins

@import pages/home
@import pages/listing
@import pages/detail

The main advantages come from the fact that SASS @import creates a global namespace, while the Sprockets directives do not.

Using the Sprockets Directives method, working in the ‘pages/home.sass’ file, you have to do this:

home.sass (using Sprockets method)

@import partials/variables
@import partials/typography
@import vendor/mixins

.home-layout
  color: CornflowerBlue

While, using the SASS @import method, you don’t need to re-@import at all. All files @import’ed lower in the order already have access to all the variables and mixins defined in the files loaded above it in application.sass.

Some may not call this a “problem”, but aside from being annoying to do every time, there also a more serious problem; any file that contains renderable CSS (anything excluding variables, placeholders and mixin definitions) will be rendered every time it is @import’ed. This can quickly grow your final CSS output (I’ve seen some minified CSS > 1MB because of this error) and create a mass of duplicate selectors, putting undue load on the browser.

Softer Benefits:

  • Using the @import global namespace creates a Whorfian effect where the developers on the team tend to define and reuse their variables where they should (in the variables files), and not in more specific files. For example, z-indexes can become a nightmare if not defined in a global variables file.
  • Compilation will speed up a bit in development, because it won’t have to re-compile  all the vendor mixins every time each partial @import’s it.
  • SASS @import syntax is easier to read than the Sprockets CSS comments syntax, IMO.

And Lastly…

Just to appeal to higher authority (why not?), this practice is recommended on the Rails Asset Pipeline guide:

Rails Asset Pipeline advice on @import

And in CAPS on the sass-rails gem readme:

Sass-rails gem advice on @import

 Thanks for reading!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Cameron Cundiff

Testing accessibility with RSpec and Capybara

Cameron Cundiff
Tuesday, October 2, 2012

Edit 04/07/13: See the followup article for an alternative to using skip navigation links.

An exploration in automated accessibility testing

Today Grant Hutchins and I took on several stories to enhance the accessibility of a site. One of them was to add a skip-navigation link to the application.

To understand why skip-nav links are important, visit Jim Thatcher’s explanation.

Our immediate inclination was to write a request spec with Capybara to drive out the solution. We came up with the following.

The Test

require "spec_helper"

feature "Keyboard Navigation" do
  scenario "hidden skip navigation link shows when focused and jumps to content", js: true do
    login_as(users(:user))
    visit root_path

    skip_link = page.find("#skip-navigation a")
    skip_link.should have_content "Skip navigation"
    skip_link.native.location.y.should be < 0

    body_element = page.find("body")
    body_element.native.send_keys(:tab)
    skip_link.native.location.y.should == 0

    skip_link.native.send_keys(:return)
    skip_link.native.location.y.should be < 0

    current_url.should match(/#content$/)
  end
end

The Markup

%body
  #skip-navigation
    %p= link_to "Skip navigation", "#content", tabindex: 0
    ...
  #content
    ...

The Styles

body {
  #skip-navigation {
    a, a:hover, a:visited {
      position:absolute;
      left:0px;
      top:-500px;
      overflow:hidden;
    }

    a:active, a:focus {
      position:absolute;
      left:0;
      top:0;
    }
  }
}

What’s happening here?

We are asserting that the “hidden skip navigation link shows when focused and jumps to content” when clicked.

The most important aspect of what we did was emulating keyboard navigation. We’re using js: true so we have access to Selenium’s native methods and thus the send_keys method. This allows us to send keypress messages to the browser.

Since we’ve used positioning to hide the element, we also have an assertion around that property.

Problems in CI!

The application behaved as expected and the tests passed locally.

When we ran the tests in CI however, the tests failed. The reason is that _the browser must retain foremost focus in the OS in order for the :focus css pseudo-selector to fire on the skip-nav element. Without the :focus style rules applied, the skip-nav element remained invisible, and the tests failed.

We tried a workaround using within_window and forcing browser focus, but couldn’t get it to work. We’ve got a few more tricks up our sleeve that we’re going to try, and will report back here.

Edit:
We added within_window to the test to force focus on the browser. This makes the test less brittle locally (because it won’t fail if you click out of the window).

window = page.driver.browser.window_handles.last
page.within_window(window) do
  skip_link.native.location.y.should == 0
end
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

CSS :first-child, :nth-child, and :last-child are not like :eq

Mark Rushakoff
Sunday, August 26, 2012

One mistake I’ve seen made a few times is the notion that CSS’s nth-child pseudoselector acts like jQuery’s :eq pseudoselector.

jQuery’s :eq(n) pseudoselector gives you a single element that is at index n out of all matched elements. While this is certainly a useful selector to have, it’s unfortunately not supported in standard CSS. If you find yourself repeatedly using :eq in your jQuery code, be careful that you are not relying too heavily on :eq to the point where your styles are difficult to match in “pure” CSS.

If we were to express :nth-child in terms of the :eq selector, it would be like using :eqscoped to all of the immediate descendant contents of a single element. Or in my own words, :nth-child adds a constraint to the selector that the matched element must be the nth element in its parent container.

So if we had a snippet of HTML like

<div>
    <div id="bar1" class="foo"></div>
    <div id="bar2" class="foo"></div>
    <div id="bar3" class="foo"></div>
</div>

Then the selector .foo:nth-child(2)will match the div #bar2. If we insert another element at the front of the container:

<div>
    <p>Shift!</p>
    <div id="bar1" class="foo"></div>
    <div id="bar2" class="foo"></div>
    <div id="bar3" class="foo"></div>
</div>

And again we select .foo:nth-child(2), we match the div #bar1 because the 2nd child of the container also matches .foo.

Thus, in this second example, if we try .foo:nth-child(1) or the equivalent .foo:first-child, we will not match any elements because the first child element in that container — the p tag — does not match .foo.

Likewise, :nth-child can match children in multiple containers. In the HTML snippet:

<div>
    <p>Shift!</p>
    <div id="bar1" class="foo"></div>
    <div id="bar2" class="foo"></div>
    <div id="bar3" class="foo"></div>
</div>

<div>
     <div id="quux" class="foo"></div>
</div>

the selector .foo:last-child will match the divs #bar3 and #quux; but .foo:first-child or .foo:nth-child(1) will only match #quux because the first child of the first container is, again, not a .foo.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Tyler Schultz

[Standup][SF] 2012.05.25 – 1 git repo, 2 Procfiles, 2 Heroku Apps, CSS transitions behaving badly

Tyler Schultz
Friday, May 25, 2012

Ask for Help

*”1 git repo, 2 Heroku apps, 2 procfiles? Heroku currently is limited to 1 procfile per repo, so we’ve created a rake task that branches, modifies the procfile and pushes. Do you have a better solution?”

Is it possible to use env variables to parameterize your Procfile?

“Capybara: How can I click on a flash dialog for webcam settings?”

This was solved by right clicking and going into flash settings and enabling this permission always for this domain. Setting this up on headless CI may be more difficult.

“I have CSS transitions that behave differently when ‘user initiated’ vs initiated from a setTimeout or other event.”

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

Unwanted whitespace between elements

Mark Rushakoff
Saturday, January 21, 2012

We recently came across a situation in our markup where we wanted whitespace in the markup for readability, but we didn’t want that whitespace represented between the elements.

We found a fix that suggested using font-size: 0 in CSS to eliminate the whitespace. That worked fine in Chrome, but we found that in Firefox, the containing element no longer scrolled with the mouse wheel or arrow keys! Apparently Firefox’s scroll speed is proportional to font-size.

Here’s a jsFiddle demonstrating the issue (open in Firefox to see the problem, of course).

Ultimately the best solution for us was to eliminate the whitespace in the markup. This StackOverflow question lists a couple creative ways to solve the same problem (using comments in place of whitespace, leaving the whitespace inside the tag).

The CSS3 draft (currently) specifies a text-space-collapse property, but we are targeting IE8 among other browsers, and the draft doesn’t seem to be finalized anyhow.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Alex Welch

Serving up different sized dynamic images based on device resolutions

Alex Welch
Thursday, October 20, 2011

Serving up different sized dynamic images based on device resolutions.

Jason and I were working on an app where we needed to render dynamic images of several different sizes for different mobile devices, depending on device resolution.

Our scenario was analogous to the following:

Let’s say you are an engineer for Twitter and you need to display a user’s avatar on their show page, but you need to serve a small, medium, or large image based on the resolution of the device accessing the page.
This is a potential candidate for CSS media queries, except that the image url needs to be obtained from our User object (in Ruby).
Let’s cross that bridge when we get there and spike on an initial proof-of-concept.

users#show view
<h2><%= @user.name %></h2>
<div class="avatar"></div>
# ...
stylesheet
/* Default - screens over 767px wide */
.avatar {
  /* ... */
  width: 220px;
  height: 220px;
  background: url('/assets/dfp/large.jpg');
}

/* Mobile Landscape */
@media only screen and (min-width: 480px) and (max-width: 767px) {
  .avatar {
    /* ... */
    width: 140px;
    height: 197px;
    background: url('/assets/dfp/medium.jpg');
  }
}

/* Mobile portrait */
@media only screen and (max-width: 479px) {
  .avatar {
    /* ... */
    width: 60px;
    height: 85px;
    background: url('/assets/dfp/small.jpg');
  }
}

Pretty straightforward stuff, especially if you’ve followed the Responsive Web Design (CSS media queries) trend.
The interesting thing to note here is that when putting the background image in the stylesheet, the asset does not get requested until you resize your browser to the size that uses that image.
Go ahead and load this page in a web browser, open up the network panel, resize the display, and watch the asset size change and different requests getting fired off. That’s exactly what we want!

Okay, great. But, although it would be glorious, not everyone is going to have Dog Fanny Pack for their avatar. We need to call some ruby method on some ruby object to get the image (e.g. user.avatar.path).
Not really something you can do from within the stylesheet. Alternatively, you wouldn’t want to move the background image reference to the view because then it gets loaded as soon as the page loads, regardless of the screen resolution.

To make this puppy (pun intended) dynamic, we create a little proxy. See below:

Routes
ResponsiveUserAvatar::Application.routes.draw do
  # ...
  match "users/avatars/:size.jpg" => "users#avatar"
end
Users controller
def avatar
  user = get_user
  size = params[:size]
  if user.present?
    send_file "#{Rails.root}/#{user.avatar.path(size)}"
  else
    render :status => :not_found, :text => "not found"
  end
end

We create an action, called avatar, on our users controller (you also create a separate avatars controller) that takes a size parameter. The avatar action first looks up the user (You don’t get to see how ’till later),
then it grabs the size from the url and renders the user’s avatar for that size.

Quick aside

You may notice this action isn’t really on the member (i.e. no user id), even though it should be. We’ll get to that in a second.
You may also be thinking of alternatives to using send_file. Jason and I experimented with redirects, but ran into caching issues. I am open to suggestions on these topics, so feel free to post feedback in the comments or submit a pull request to the demo app.

Back to business

Now all we have to do is call our proxy image/action in the stylesheet, see below:

users.css
/* Default - screens over 767px wide */
.avatar {
  /* ... */
  background: url('/users/avatars/large.jpg');
}

/* Mobile Landscape */
@media only screen and (min-width: 480px) and (max-width: 767px) {
  .avatar {
    /* ... */
    background: url('/users/avatars/medium.jpg');
  }
}

/* Mobile portrait */
@media only screen and (max-width: 479px) {
  .avatar {
    /* ... */
    background: url('/users/avatars/small.jpg');
  }
}

Coming clean…

So, I left out one minor detail… Okay major detail… It’s time to show the implementation of the “get_user” method.

users_controller
class UsersController < ApplicationController
  # ...
  private

  def get_user
    if request.env["HTTP_REFERER"].present?
      user_id = request.env["HTTP_REFERER"].match(//(d+)/?/)[1]
      user = User.find_by_id(user_id)
    end
  end
end

In our case we always had the user id in the page that used the avatar. If we tried to implement this on the listing page… Well it wouldn’t be pretty.

While this isn’t a silver bullet solution, it’s a cool concept and can be applied to many different applications. I call it the “responsive-css-background-fake-image-proxy” pattern.
Okay, maybe not, but to recap, the main components are:

  1. Use CSS media queries to target different device resolutions.
  2. Reference the background-image proxy url in the stylesheet, which only loads the image size needed.
  3. Use a fake image proxy to get your dynamic image.

Demo app and demo app code

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
David Stevenson

Standup 4/28/2010: Webrat threading errors & new RubyMine version

David Stevenson
Wednesday, April 28, 2010

Ask for Help

“We keep getting webrat thread exceptions running our integration specs with the rails integration runner: Thread tried to join itself. The error message varies with different versions of ruby 1.8.6 vs 1.8.7.”

Anyone had this problem or know why?

“How do I skin an iphone mobile site to be the correct width so it’s not 980px wide?”

<meta name="viewport" content="width = device width" />

*”We’re trying to deploy some nginx configuration changes to EngineYard Cloud, what’s the right way to do that?”

We’ve tried building custom chef recipes to solve this problem, but they run after nginx has already restarted, so are a poor solution to this problem. The better solution might be to check in configuration files into the application and symlink them into the nginx configuration directory using a before_symlink.rb hook in the /deploy directory.

*”We’ve got a has_many association where some of the child records are originally saved in an invalid state. When we later load the parent and ask it if it’s valid, it returns true even with validates_associated. How can we get the desired validation behavior?”

Turns out that unloaded associations are not validated. Solution: load the association before calling .valid? on the parent. In general, you should also not create invalid objects, instead using a state variable to put them into a “draft” or “incomplete” state where they are still valid but not complete. Then remove that state and you’ll see the errors required to finish that object.

Interesting Things

  • When RubyMine 2.0.1 won’t run your focused specs, try attaching rspec 1.2.9 to it rather than 1.3.x. It fixed this issue for one of our teams.
  • Rubymine 2.0.2 came out today: can finally run focused contexts?! Also including bundler support! What’s new
  • We tried our Unicorn on EngineYard cloud: so far so good. It’s still “experimental” but seems to work.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

opacity (or, a paucity of transparency)

Alex Chaffee
Sunday, December 13, 2009

The rules for how to make parts of your HTML page translucent are kind of hard to understand — in other words, the opacity rules are pretty opaque. (Anyone who can make that into a good pun, let me know and I’ll change the title of this article accordingly.) The following represents the results of a couple of days of empirical research and as such may be incomplete or inadequate, but here goes.

In the brave new HTML5 world, with all the CSS gizmos supported by Safari and Chrome and Firefox, there are now three ways to make things translucent. And none of them works quite the way I naïvely expected.

One. Use the “opacity” CSS attribute. This attribute works pretty well… at first. It applies to an element and all its children, but according to the spec it’s meant to act as an upper bound on the opacity of all its children, and while it can technically be overridden, the overridden value is applied as a multiplier to the previous value, not as a whole separate value. So if you want some fully opaque children inside a translucent container, you can’t get there from here. The children are always going to be at least as transparent as the parent — in other words, they can’t transcend their parent’s transparency.

This is spelled out in detail in https://developer.mozilla.org/En/Useful_CSS_tips/Color_and_Background and as a solution they propose either pulling the child out of the normal hierarchy (ugh — that means you lose all the other CSS inherited styles and positioning), or …

Two. Make an alpha channel PNG and use it as the parent’s background, probably with background-repeat:repeat. This is adequate, except that there’s now another, cleaner way…

Three. For the parent, use background-color: rgba(255, 255, 255, 0.5) (where ’0.5′ is the opacity and ’255,255,255′ is the decimal RGB value) — that will work the same as an alpha PNG but without needing to go round-trip to Photoshop every time you want to change the color or level. Much better.

I have no idea what the level of support for rgba background colors is, but it seems to work in the latest Safari and Firefox so I’m happy.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (783)
  • rails (117)
  • testing (90)
  • ruby (86)
  • ruby on rails (71)
  • jobs (62)
  • javascript (59)
  • techtalk (44)
  • ironblogger (42)
  • rspec (39)
  • bloggerdome (34)
  • productivity (34)
  • activerecord (30)
  • rubymine (30)
  • git (29)
  • gogaruco (29)
  • nyc (27)
  • design (24)
  • mobile (23)
  • pivotal tracker (22)
  • process (21)
  • cucumber (21)
  • jasmine (19)
  • ios (18)
  • tracker ecosystem (17)
  • webos (17)
  • objective-c (17)
  • fun (16)
  • android (16)
  • palm (16)
  • ci (16)
  • "soft" ware (16)
  • bdd (15)
  • tdd (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • css (14)
  • gem (13)
  • mouse-free development (12)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • api (12)
  • keyboard (11)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
Subscribe to css Feed
  1. 1
  2. 2
  3. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >