Overview
AngularJS Material's Layout features provide sugar to enable developers to more easily create modern, responsive layouts on top of CSS3 flexbox. The layout API consists of a set of AngularJS directives that can be applied to any of your application's HTML content.
Using HTML Directives as the API provides an easy way to set a value (eg. layout="row"
) and
helps with separation of concerns: Attributes define layout while CSS classes assign styling.
HTML Markup API | Allowed values (raw or interpolated) |
---|---|
layout | row | column |
flex | integer (increments of 5 for 0%->100%, 100%/3, 200%/3) |
flex-order | integer values from -20 to 20 |
flex-offset | integer (increments of 5 for 0%->95%, 100%/3, 200%/3) |
layout-align | start|center|end|space-around|space-between start|center|end|stretch |
layout-fill | |
layout-wrap | |
layout-nowrap | |
layout-margin | |
layout-padding | |
show | |
hide |
And if we use Breakpoints as specified in Material Design:
We can associate breakpoints with mediaQuery definitions using breakpoint alias(es):
Breakpoint | MediaQuery (pixel range) |
---|---|
xs | '(max-width: 599px)' |
gt-xs | '(min-width: 600px)' |
sm | '(min-width: 600px) and (max-width: 959px)' |
gt-sm | '(min-width: 960px)' |
md | '(min-width: 960px) and (max-width: 1279px)' |
gt-md | '(min-width: 1280px)' |
lg | '(min-width: 1280px) and (max-width: 1919px)' |
gt-lg | '(min-width: 1920px)' |
xl | '(min-width: 1920px)' |
API with Responsive Breakpoints
Now we can combine the breakpoint alias
with the Layout API to easily support Responsive breakpoints
with our simple Layout markup convention. The alias
is simply used as suffix extensions to the Layout
API keyword.
e.g.
This notation results in, for example, the following table for the layout
and flex
APIs:
layout API | flex API | Activates when device |
---|---|---|
layout | flex | Sets default layout direction & flex unless overridden by another breakpoint. |
layout-xs | flex-xs | width < 600px |
layout-gt-xs | flex-gt-xs | width >= 600px |
layout-sm | flex-sm | 600px <= width < 960px |
layout-gt-sm | flex-gt-sm | width >= 960px |
layout-md | flex-md | 960px <= width < 1280px |
layout-gt-md | flex-gt-md | width >= 1280px |
layout-lg | flex-lg | 1280px <= width < 1920px |
layout-gt-lg | flex-gt-lg | width >= 1920px |
layout-xl | flex-xl | width >= 1920px |
Below is an example usage of the Responsive Layout API:
<div layout="column" class="zero">
<div flex="33" flex-md="{{ vm.box1Width }}" class="one"></div>
<div flex="33" layout="{{ vm.direction }}" layout-md="row" class="two">
<div flex="20" flex-md="10" hide-lg class="two_one"></div>
<div flex="30px" show hide-md="{{ vm.hideBox }}" flex-md="25" class="two_two"></div>
<div flex="20" flex-md="65" class="two_three"></div>
</div>
<div flex class="three"></div>
</div>
This Layout API means it is much easier to set up and maintain flexbox layouts vs. defining everything via CSS. The developer uses the Layout HTML API to specify intention and the Layout engine handles all the issues of CSS flexbox styling.
The Layout engine will log console warnings when it encounters conflicts or known issues.
Under-the-Hood
Due to performance problems when using Attribute Selectors with Internet Explorer browsers; see the following for more details:
Layout directives dynamically generate class selectors at runtime. And the Layout CSS classNames and styles have each been
predefined in the angular-material.css
stylesheet.
Developers should continue to use Layout directives in the HTML markup as the classes may change between releases.
Let's see how this directive-to-className transformation works. Consider the simple use of the layout
and flex
directives (API):
<div>
<div layout="row">
<div flex>First item in row</div>
<div flex="20">Second item in row</div>
</div>
<div layout="column">
<div flex="66">First item in column</div>
<div flex="33">Second item in column</div>
</div>
</div>
At runtime, these attributes are transformed to CSS classes.
<div>
<div class="ng-scope layout-row">
<div class="flex">First item in row</div>
<div class="flex-20">Second item in row</div>
</div>
<div class="ng-scope layout-column">
<div class="flex-33">First item in column</div>
<div class="flex-66">Second item in column</div>
</div>
</div>
Using the style classes above defined in angular-material.css
.flex {
-webkit-flex: 1 1 0%;
-ms-flex: 1 1 0%;
flex: 1 1 0%;
box-sizing: border-box;
}
.flex-20 {
-webkit-flex: 1 1 20%;
-ms-flex: 1 1 20%;
flex: 1 1 20%;
max-width: 20%;
max-height: 100%;
box-sizing: border-box;
}
.layout-row .flex-33 {
-webkit-flex: 1 1 calc(100% / 3);
-ms-flex: 1 1 calc(100% / 3);
flex: 1 1 calc(100% / 3);
box-sizing: border-box;
}
.layout-row .flex-66 {
-webkit-flex: 1 1 calc(200% / 3);
-ms-flex: 1 1 calc(200% / 3);
flex: 1 1 calc(200% / 3);
box-sizing: border-box;
}
.layout-row .flex-33 {
max-width: calc(100% / 3);
max-height: 100%;
}
.layout-row .flex-66 {
max-width: calc(200% / 3);
max-height: 100%;
}
.layout-column .flex-33 {
max-width: 100%;
max-height: calc(100% / 3);
}
.layout-column .flex-66 {
max-width: 100%;
max-height: calc(200% / 3);
}