Posts Tagged ‘CSS’

Vertical centering with flexbox

I’ve only begun delving into doing layouts with flexbox (CSS Flexible Box Layout), but one immediate use case is vertical centering, which has been a pain point in web design since the transition away from table-based layouts.

HTML

<body>    
<
div class="flex-container">    
    <
p class="centered-element-within-body">Center Me</p>            
</
div>
</
body>

CSS

* { margin:0; padding:0; border:none; box-sizing:border-box; }
html, body { width:100%; height:100%; overflow:hidden; }

.flex-container { width:100%; /* width of body (fluid) */
height:100%; /* height of body (fluid) */
display:flex; /* flex display */
flex-direction: row; /* flow of elements in container */
justify-content: center; /* alignment along the main axis (x-axis, since the flex-direction = row) */
                    
align-items: center; /* alignment along the secondary axis (y-axis) */            
                    
border: 5px solid #2C81F5;                    
                }
                
.centered-element-within-body { background:#2C81F5; color:#fff; }

A look at Adobe Edge Animate

I recently played around a bit with Adobe Edge Animate, as I was searching for an SVG animation tool, and jotted down a few notes on my impression of the editor.

Adobe Edge Animate CC 2014
  • The timeline and visual preview are excellent, it’s refreshing to have something like this available for web animations. I did notice a tendency for the preview to tear and flicker when animating but, overall, it’s a minor annoyance.
  • The output is not cross-platform, the generated code is heavily webkit-based and depends on vendor-prefixed styles (-webkit-filter) for certain effects. It’s cool to see the effect and have them in the editor, but it really doesn’t achieve a “write once, run anywhere” development process.
  • This is not an SVG animation tool. I expected transitions and transformation on SVG elements (groups, paths, etc.), instead what’s generated is CSS3 transitions/transformations on a <div> element (the SVG document is simply put as the background-image of the <div>). This severely limits what can be done. Much richer and expressive animations could be achieved by allowing manipulating the points and control points on individual SVG elements.

It’s disappointing that despite being an incredibly visual medium, most web design tasks are still done by writing linear blocks of code. Animation is a task well suited for a WYSIWYG editor and Edge Animate is ultimately a step in the right direction, but it’s basis on CSS3 transition and transform puts some hard limits on what can be achieved and I can’t see myself using it for anything substantial.

Entering the world of high-DPI displays

With a Retina iPad and my recent purchase of a Yoga 2 laptop with a “Quad HD” display (3200×1800) I’ve been dragged into the world of high-DPI (more precisely PPI) displays. For years, DPI was “standard” at either 96dpi (Windows) or 72dpi (Mac OS), with a logical/software pixel being equivalent to a hardware pixel on the display device. A higher resolution monitor meant the content on your display got a bit smaller but you gained a couple more thousand pixels to work with, but the recent and massive increases in pixel densities seems to be the end of the 1:1 mapping between software and hardware pixel references. Below are a few notes on my experiences dealing with high-DPI displays and content so far.

  • Windows 8.1 support is terrible. Both application support and operating system support for high-DPI displays is abysmal. See the post Living a High-DPI desktop lifestyle can be painful by Scott Hanselman which reflects many of the issues I’ve encountered with my Yoga 2 as well. There’s a large list of issues: for non-DPI aware applications Windows scale text but not icons and layout, applications lie about being DPI-aware and are rendered too small, and some applications simply crash (TourtiseSVN’s diff… no clue why, too many pixels?!). It’s easy to wag a finger at application developers, but legacy support is clearly something the operating system needs to handle. In addition, despite Windows 8.1 touting automatic, per-monitor, DPI detection, it’s all based off of the DPI of a “primary monitor” and content on the other monitors is scaled to match. So dragging a window for an application from the Yoga 2 display across to a HD/96dpi monitor results in the window being scaled down (and visibly blurry). Worse, all applications undergo the same treatment – so if you’re thinking you can just use non-DPI aware applications on an external display until support comes around, guess again.
    ArsTechnica did a piece mentioning this issue in particular, and Windows 8.1’s high-DPI support is general.
  • Web support is only half-way there. The best thing done to support high-DPI displays was defining the CSS2 reference pixel to be independent of hardware pixels. Beyond that you have media queries and higher resolution background images, but there’s still no good way to specify alternate foreground images, though the <picture> element may gain support soon. In general, outside of CSS things gets messy, as is the case with a high-DPI <canvas>.
    One problem with the web that I don’t see a proposed solution for is handling low-resolution image assets for which you can’t get a higher resolution version. This is a problem I face with this blog. There’s a lot of images (old screenshots, low-resolution photos, etc.) for which I can’t get a 2x, 4x, etc., higher resolution version and there’s no way to prevent upscaling the images or specify how the upscaling is done. The typical 2x-bilinear-filtered upscaling, done by most browsers, is not always desirable. In addition, as display vendors pack more pixels in, what happens when the “high-resolution” version needed is 4x or 8x?
  • SVG/Vector-based images aren’t always the answer. There’s a lot of benefits to vector-based formats, but they’re not the holy grail many think they are. For vector-based images, rendering costs grow as you add details with polygons and paths. It’s why video games still rely heavily on texture mapping, even as graphics hardware has progressed to handle rendering millions of polygons per frame – the additional geometry and computation for fine details is enormous.

Triggering reflow to toggle a CSS3 transition

My previous post on triggering reflow focused on forcing reflow to allow for transitions when an element is put into the DOM render tree. This post doesn’t present any new concepts, but provides an example of triggering reflow, in the same manner, to allow for applying style changes to a DOM element instantly and without a transition, then turning the transition back on.

The changes to an element are typically:

  • Turn off the transition on the element
  • Update some properties of the element (that are part of the transition), and force reflow so that the changes are applied instantly without transition
  • Turn on the transition again

In working with transitions, this scenario has come up frequently for me, as much as dealing with DOM elements being put into the render tree.

One classic example where this becomes necessary is in constructing a circular carousel, as the trick to make it circular is to make the first slide a copy of the last slide – so the carousel starts on the second slide and when you reach the last slide, the carousel instantly jumps to the first slide and slides over to the second slide. This is all invisible to the user, and it appears that the carousel has transitioned smoothly from the last slide to the first slide.

The code for a working circular carousel with 3 slides (plus a copy of the last slide) is presented below, with the classes for the different states of the slides being slide1pre (copy of slide 3), slide1, slide2, and slide3.

Note the point where it is necessary to trigger reflow in order to invisibly jump to the first slide.

.carousel-viewport { width:70px; height:70px; overflow:hidden; }
.carousel-container { width:1000px; }

.carousel-container.notransition { transition:transform 0s; }
.carousel-container.dotransition { transition:transform 0.5s; }

.carousel-container.slide1pre { transform:translateX(0px); }
.carousel-container.slide1 { transform:translateX(-70px); }
.carousel-container.slide2 { transform:translateX(-140px); }
.carousel-container.slide3 { transform:translateX(-210px); }

.test-block { width:50px; height:50px; float:left; margin:10px; color:#fff; background:#222; }
<p><a class="ia-start-color-change" href="#">Rotate carousel</a></p>

<
div class="carousel-viewport">
<
div class="ia-carousel-container carousel-container dotransition slide1">
<
div class="ia-slide-pre test-block">3</div>
<
div class="ia-slide-1 test-block">1</div>
<
div class="ia-slide-2 test-block">2</div>
<
div class="ia-slide-3 test-block">3</div>
</
div>
</
div>
var curSlide = 1; // start at slide1

$('.ia-start-color-change').click(function (event) {

var testBlockElem = $('.ia-carousel-container');

// slide 1 to slide 2
if (curSlide == 1) {
testBlockElem.removeClass(
'slide1').addClass('slide2');
}

// slide 2 to slide 3
if (curSlide == 2) {
testBlockElem.removeClass(
'slide2').addClass('slide3');
}

// slide 3 to slide1pre, then slide1pre to slide1
if (curSlide == 3) {

// turn off transition
testBlockElem.removeClass('dotransition').addClass('notransition');
// go to slide1pre invisibly and instantly (w/o transition)
testBlockElem.removeClass('slide3').addClass('slide1pre');

//
// Force reflow to commit style changes to DOM
// allows us to re-apply transition rule, with the DOM updated to the carousel on slide1pre with no transition rule
//
testBlockElem[0].offsetWidth; // force reflow
//

// re-apply transition rule
testBlockElem.removeClass('notransition').addClass('dotransition');
// transition over to slide1
testBlockElem.removeClass('slide1pre').addClass('slide1');

// reset slide counter
// (note subsequent increment in this function, so we'll be at curSlide=1 when this function finishes)
curSlide = 0;
}

curSlide++;

event.preventDefault();
});

Triggering reflow for CSS3 transitions

There’s a lot written on minimizing reflow of the DOM, but one interesting situation is actually trying to force reflow in order to apply a CSS transition rule when the element is pushed into the DOM render tree (e.g. display:none to display:block, display:inline, etc.).

Problem

.test-block { width:50px; height:50px; background:#000; margin:10px; opacity:1; transition:opacity 0.5s; }
.test-block.invisible { opacity:0; }
.test-block.hide { display:none; }
<div class="ia-fadein-block test-block invisible hide"></div> $('.ia-fadein-block').removeClass('hide');
$(
'.ia-fadein-block').removeClass('invisible');

If we remove the hide and invisible classes from the div (as shown above), you’d assume that the div would transition smoothly to opacity:1 in 0.5s; however, this is not the case, the div will go to opacity:1 instantly.

What’s happening is that the removal of both classes occur prior to the browser adding the div to the DOM render tree; when the div gets rendered, it’s as if it never had the hide nor invisible class.

Reflow needs to be triggered before the invisible class is removed in order for the transition to work as expected.

Deprecated solution: setTimeout(func,0)

A setTimeout() with a delay of 0 was my go-to solution for the longest while. Here, the function argument specified would handle whatever needed to occur after the element was added to the DOM render tree (for the example presented above, this would mean the invisible class being removed in the function specified). The thinking behind using setTimeout() was that reflow would occur at some point in the current execution context and before the execution of the setTimeout() callback. This seemed true for a while, but with one of the Firefox releases last year (I don’t know specifically which) I noticed things breaking, with the Javascript engine executing the callback before reflow occured.

I did some quick hacks to fix existing code by increasing the time span before the timeout was triggered (typically 50ms-100ms), but this made a nasty hack even nastier and I wanted a more reliable solution.

Current solution: Trigger reflow manually

There are a number of calls that will trigger reflow on the DOM, but the most reliable calls, that always force reflow, seem to be the ones that return any sort of measurement that must be calculated (e.g. offsetWidth) on an element. With this in mind, the Javascript code can be modified as follows:

$('.ia-fadein-block').removeClass('hide');

// force reflow
$('.ia-fadein-block')[0].offsetWidth;
//

$('.ia-fadein-block').removeClass('invisible');

The code is for demonstration purposes; for repeated use, the hack to force reflow should really be encapsulated in a function, as there is no guarantee that the reflow behavior triggered by querying offsetWidth will remain consistent.

Ideal solution: API Method to trigger reflow or delay certain style changes post-reflow

The solution presented above is still a hack and may very well break in the future, as there is no guarantee that browsers won’t cache properties like offsetWidth in further attempts to minimize reflow. A robust, future-proof, solution is needed and it’s amazing one hasn’t come to fruition as yet.

A Mozilla bug report documents this issue and David Baron presents some workable solutions.

Interaction classes – seperating CSS styles from Javascript interactions

Something I’ve been doing for a while in my web development work is applying separate classes, interaction classes, to DOM elements that interact with Javascript. Basically, an interaction class is applied to any DOM element touched by Javascript code – an element bound to an event handler, an input element with it’s value being read or written, an element selected for animation, etc. The goal being to de-couple styling from interaction, allowing style changes to not interfere with JS code, and vice-versa.

Below is a bit of code to demonstrate what I’m talking about. As a convention, I apply a “ia-” prefix to my interaction classes.

<a href="#" class="btn-primary ia-begin-testing">Begin Testing</a>
  • btn-primary has the CSS rules for styling the anchor as a button
  • ia-begin-testing is bound to a JS event that triggers some arbitrary “begin testing” action

If the future, if I want to change the button to a link (remove the btn-primary class), change it to a secondary button (btn-primary to btn-secondary), or change styling in any other way, the Javscript code is unaffected and requires no changes.

In addition, the ia-begin-testing class can also be applied to other elements (another button, a link, an anchor wrapping an image, etc.) and is automatically bound to the same interaction functions, without writing additional JS DOM selection code. The ia-begin-testing class can also be removed, or changed to another interaction class, and the styling on the button remains the same.

While IDs and data attributes are also good choices for architecting this sort of style/interaction separation, I like classes for 2 reasons:

  • Selection via class is relatively fast across all browsers compared to selection via data attributes
  • Compared to IDs, classes can be re-used allowing the same interactions to be shared by multiple elements (e.g. a button and a link can both trigger the same function)

One of the reasons I wrote this post is as an alternative to the the “grouping of selectors” approach presented in Chris Coyier’s Can You “Over Organize” JavaScript? article. With interaction classes, there’s little need for grouping selectors. Aside from the benefit of de-coupling styling and interaction, you get the advantage of a single class (ia-whatever), on whatever and however many elements, mapping all said elements to their necessary JS functions. With grouping of selectors, some sanity is brought to the scattered DOM selection code, but you’re left with the burden of maintaining a pool of different element IDs, classes, etc.; a chore that only gets harder as the codebase grows and changes.

Better Checkboxes

Another take on styling checkboxes with jQuery+CSS by Martin Angelov.

Better Check Boxes with jQuery and CSS by Martin Angelov

I’m not sure if they should really be called checkboxes at this point. I did something very similar a while ago, I called them toggle buttons.

jQuery toggle button

On most of the mobile platforms you’ve probably seen a toggle, switch-style, button used as a replacement for a checkbox. I took a stab at doing something similar in HTML, CSS and Javascript.

toggle button

You can see the final result here (it’s a pain in the ass to embed it)

Note that while I used jQuery, this is not a jQuery extension. It doesn’t use that much jQuery and I really don’t get the desire to make everything-and-the-kitchen-sink a jQuery plugin.

The button depends upon 2 images, a base, containing the design and both states of the button:

toggle button base

… and a frame (optional if you can get away with using CSS borders):

toggle button frame

(note, the middle is transparent, not white)

The HTML and CSS consists of a:

  • A div, which has the its background-image set to the base and sized to the button’s inner area, roughly half the width (in this case, plus a few pixels as some pixels were shared by both states of the button) of the base and the same height
  • A block-level anchor element within the div, which has its background-image set to the frame and sized to the same area as the frame image. The anchor allows the area to be clickable and we’ll respond to the click event that occurs on this element.
  • An input checkbox which will store the checked/unchecked state of the button.
<div style="margin:0; padding:0; background:url(base.png) -41px 1px no-repeat transparent; width:46px; height:20px;">
<a class="toggle-button" href="#" style="margin:0; padding:0; display:block; background:url(frame.png) 0 0 no-repeat transparent; width:48px; height:20px;">
<input style="display:none;" type="checkbox" />
</a>
</div>

The Javascript code to handle the click event, where the background is shifted left or right when the button’s state is toggled using jQuery’s animate function,

$('.toggle-button').click(function ()
{
if (!$('input', this).is(':checked')) {
$(
this).parent().animate({ "background-position": "0px 1px" }, "slow");
$(
'input', this).attr('checked', true);
}
else {

$(
this).parent().animate({ "background-position": "-41px 1px" }, "slow");
$(
'input', this).attr('checked', false);
}

return false;
});

This all works great, but it’s not-so-great as a reusable component, so I encapsulated the code so that I could easily transform a div, such as the one shown below, into the toggle button.

<div id="my_toggle_button"></div>

Central to this is creating a ToggleButtonFactory, which will make the button by inserting the necessary HTML/CSS code into the DOM and bind the anchor to the click event. There’s also a ToggleButton object created by the factory which will have methods to toggle the button state (.toggle) and get the state of the button (.val).

function ToggleButton(_element, _funcSelectYes, _funcSelectNo)
{
this.jqDomElement = _element;
this.funcSelectYes = _funcSelectYes;
this.funcSelectNo = _funcSelectNo;

this.val = function ()
{
return $(this.jqDomElement).find('input').is(':checked');
}

this.toggle = function (funcSelectYes, funcSelectNo)
{
if (!this.jqDomElement.find('input').is(':checked')) {
this.jqDomElement.animate({ "background-position": "0px 1px" }, "slow");
this.jqDomElement.find('input').attr('checked', true);

if (this.funcSelectYes) {
this.funcSelectYes();
}
}
else {

this.jqDomElement.animate({ "background-position": "-41px 1px" }, "slow");
this.jqDomElement.find('input').attr('checked', false);

if (this.funcSelectNo) {
this.funcSelectNo();
}
}
}
}

var ToggleButtonFactory = {};
ToggleButtonFactory.makeButton =
function (element, initialState, funcSelectYes, funcSelectNo)
{
if ($(element).is('div')) {

var elemId = $(element).attr('id');
var newDivId = '__toggle_button_div_' + Math.ceil((Math.random() * 100000));
$(element).replaceWith(
'<div id="' + newDivId + '" style="margin:0; padding:0; background:url(base.png) -41px 1px no-repeat transparent; width:46px; height:20px;"><a class="toggle-button" href="#" style="margin:0; padding:0; display:block; background:url(frame.png) 0 0 no-repeat transparent; width:48px; height:20px;"><input id="' + elemId + '" name="' + elemId + '" style="display:none;" type="checkbox" /></a></div>');

var newElem = $('#' + newDivId);
var tb = new ToggleButton(newElem, funcSelectYes, funcSelectNo);

newElem.find(
'a').click(function ()
{
tb.toggle();
return false;
});

if (initialState) {
tb.toggle();
}

return tb;
}
}

Note there’s some additional code here to deal with setting the button to an initial state and callbacks for when the button is set to the “Yes” or “No” state.

Now, to transform the my_toggle_button div shown above into a toggle button, the following is done:

var btn = ToggleButtonFactory.makeButton('#my_toggle_button', false, function () { }, function () { });

(the call can be shorter, this shows calling with all arguments and capturing the return value [the ToggleButton object])

For another take on this, see the jQuery LightSwitch plugin.

@font-face

I’ve always played it safe with fonts when it comes to web design, sticking to fonts commonly available across operating systems such as Verdana, Tahoma, Trebuchet MS, etc. However, I’m pretty psyched to see how well the CSS @font-face attribute is supported. Format support is somewhat of a mess: EOT for Internet Explorer and TTF/OTF for WebKit-based browsers (Chrome, Safari). However, Firefox 3.6+ supports the new Web Open Font Format, which is poised to become the new standard and will, hopefully, quickly find it’s way into the other browsers.

If your in Firefox, Safari, or Chrome, here’s a font I’ve loved for a while, Titillium:

TitilliumText999wt

I’ve never really had problems finding fonts for free or even commercial use, but Font Squirrel now makes the whole search process dead simple and super easy. They also seem to have a pretty awesome converter; though I used this oft2woff converter for my little demo above.

Enyo

I missed webOS Developer Day, but I took a look at the presentation of the Enyo framework (video below). I like most of the bullet points: faster performance, hardware acceleration built-in, etc. However, one point that’s troubling me is the idea of using higher-level controls instead of divs. From the bit of code presented in the final demo, it looks like layout (and pretty much all UI stuff) will be done using JavaScript widgets, which are translated at some point into the appropriate HTML constructs. Obviously, widget-centered development isn’t a new concept (MFC, WinForms, Cocoa… sproutcore and such on the web) nor is it necessarily a bad one (getting something presentable up and running is easier), but there always seems to be a very real and very large loss of flexibility.

When a widget doesn’t look or function exactly how you need it to, and it becomes necessary to make a new one, development within the widget framework can range in difficulty from trivial to near-impossible. As I mentioned when I wrote about Adobe Air, HTML/CSS isn’t perfect, but it’s the most flexible layout and styling framework I’ve come across. Abstracting away that flexibility in favor of plug-and-play widgets makes me cringe… it’s a nice idea, it’s a very (object-oriented) developer-ish idea, but it usually comes with a pretty high cost.

From working with both HTML/CSS and WinForms extensively, I’d say the widget-centered framework model used for desktop apps shouldn’t be replicated for web development. In fact, it should be the other way around: the flexibility of a HTML/CSS-esque system should be brought to the desktop.

How this will play out for Enyo, I don’t know. I’m cautiously optimistic. Being a web framework, everything still boils down to HTML and CSS, but it remains to be seen what level of manipulation will be allowed or make sense (in terms of performance, coding difficultly, etc.) at that level.