prettyprint

Showing posts with label CSS. Show all posts
Showing posts with label CSS. Show all posts

Friday, 14 February 2014

Widget based architecture - Mobile Web

In my attempt to share knowledge I would like to show you a very simple, framework agnostic, way of building highly responsive re-usable components for mobile ready websites. Mobile in this age is a default, and sorry but if you don't think that way you are already out of the game.

Widget based architecture is a concept, or a set of very simplistic rules that make all the difference. And the really cool part is that full responsiveness can be achieved using only CSS and HTML. Without the use of, learning curve heavy, third party APIs.

Blog posts with lots of text and low information are boring, so let's go into the juice. The concept is simple, let's assume that for any component of a web page that you develop you have the following rules:

  1. Any top level component that you build is a widget (has the class widget in the html)
  2. A widget is always 100% width, it doesn't matter if it is dropped in a 100px wide or a 100000px wide place. It will always center it self and gracefully addapt to the provided width.
  3. (Who controls the width then?) A widget may have children widgets, and as he knows what kind of children he has, the parent widget will override the percentage width of it's children.

So a widget is pretty much the following square, and consider the .widget notation as the class within your html (rule 1):


<div class="widget widgetName">
      ... content of your widget ...
</div>

Let's go into an example, let's imagine that you want to have a responsive component that shows three elements side by side on wider screens and on smaller ones you want only two elements per row:


The parent widget knows he has three children. These children have no idea where they are so they just take 100% of the container (rule 2). The parent though, wants them to show side by side in groups of three, so he overwrites their width (rule 3), and set's them as floaters. Which generates this CSS:

.widget.parentWidget > .widget { width: 33%; float: left; }

So the parent doesn't really care what kind of children it has, the only thing he cares is that they are widgets so they will gracefully adapt to the shorter width. Although the parent can be designed to work with certain .widget types, and in this case it can overwrite some of their "visual design" properties. i.e.:

.widget.parentWidget > .widget.specificWidget { 
 background-color: purple; 
}

What about the responsiveness? Well... the parentWidget also knows that it will be used as top level widget and wants to have some breakpoints. If he is nested somewhere, that is not his call. Its parent (grandpaWidget) will have the responsibility of overwriting its breakpoints. So the parentWidget will set breakpoints for his children as he currently sees them:

@media (max-width: 780px) {
 .widget.parentWidget > .widget { width: 50%; }
}

The parentWidget is 100% of it's container, so if the window re-sizes it will also re-size the parentWidget. This will allow us to have a responsive structure with one step.: 




This base structure allows you to place any widget wherever you want, they will always adapt. We can then iterate on it by having each widget as an atomic component that accepts a view model. Each view model containing the data to populate the widget, allowing the base webpage to not really care what kind or what order of widgets it is receiving. But that is complex enough to build another blog post, so I'll leave it for later.

I hope this helped build a base understanding of the flexibility that Widget based architecture allows you. Now, go build widgets ;)










Sunday, 22 December 2013

How to build LESS pathways with browser detection

Someone told me I should write more, so here is a new post after a bunch of months.

During the past half year I have been working on building highly optimized responsive front ends. It has been an HTML + CSS intensive project that aimed at building a collection of specialized widgets, which could be easily re-used.

The team I was working with developed some very cool new techniques. I am going to share here one of them here. Which is how to build LESS pathways that generate distinct CSS files for different browsers/device environments.

For this example lets assume that we have two distinct device targets. Mobile and Desktop devices. The detection of the user-agent is not part of this article. There are so many good libraries that it would be pointless. We'll also pretend to be building a blog interface.

Since each widget should be modular and independent. Let's split them into separate files, create a 'sharedVariables.less' file which will include colors, gutter widths and other stuff, then build a main.less file that includes them all:

less/
 - main.less
 - sharedVariables.less
 - widgets/
  - navigationWidget.less
  - blogArticleWidget.less
  - commentBlockWidget.less
  - commentWidget.less


The CSS generated from the main.less would normally be the file to import in the HTML and the less would look something like this:

@import "sharedVariables.less";

@import "widgets/navigationWidget.less";
@import "widgets/blogArticleWidget.less";
@import "widgets/commentBlockWidget.less";
@import "widgets/commentWidget.less";

And in the HTML:

<link type="text/css" rel="stylesheet" href="/css/main.css" />

This would generate a single css file that is applied to any device, but it is not what we want. Anyone who has faced web development has found the need to apply small CSS tweaks to target certain devices or even specific browsers (i.e.: IE8). So an interesting way to solve this would be to import specific CSS files that would include only the CSS needed for that target.

Using some pseudo-templating code:

$if target == DESKTOP:
 <link type="text/css" rel="stylesheet" href="/css/devices/desktop.css" />
$else if target == MOBILE:
 <link type="text/css" rel="stylesheet" href="/css/devices/mobile.css" />

This is actually easy to do using less mixins. Mixins can be triggered depending on states of variables. So if we have a certain widget which needs to have different properties on mobile and desktop, we can use them. This is how they look like:

.widget.navigationWidget {
 
 (...) /* other code */

 .adaptative-section() when (@mobile) {
  background: @mobileBackground;  
 }
   
 .adaptative-section() when (@desktop) {   
  background: @desktopBackground
 }
 .adaptative-section;
}

You probably noticed the variables @mobile and @desktop, and so far we have no reference to where they are defined. Let's change the structure of our .less files, and add two more files "mobile.less" and "desktop.less" under a 'devices' folder. These will be the files which will generate the CSS that we use to import.

less/
 - main.less
 - sharedVariables.less
 - devices/
  - mobile.less
  - desktop.less
 - widgets/
  - navigationWidget.less
  - blogArticleWidget.less
  - commentBlockWidget.less
  - commentWidget.less

We can now have our 'mobile.less' file looking like this:

@desktop: false;
@mobile: true;

@import "../main.less";

and the desktop one:
@desktop: true;
@mobile: false;

@import "../main.less";

By importing these two files directly into the CSS generation we can build CSS files that contain only the CSS required for each specific device.

Hope this is usefull. Leave a comment if it helped you.