Date post: | 27-Jan-2015 |
Category: |
Technology |
Upload: | gr8conf |
View: | 105 times |
Download: | 1 times |
Building Progressive UIs with Grails
Rob FletcherEnergized Work
Who am I?
Examples
gr8-examples.cloudfoundry.com
github.com/robfletcher/gr8-examples
What is Progressive Enhancement?
Approach to building web UIs that emphasizes:• Semantic markup• Separation of markup, appearance, behaviour• Rich appearance and
behaviour applied selectively• Adaptive design for cross-browser & cross-
device support• Distinct from 'graceful degradation’
Designing with Progressive Enhancement
http://filamentgroup.com/dwpe/
Is this worth the effort?
• Cross-browser compatibility• SEO compliance• Mobile device support• Support for assistive devices e.g.
screenreaders• Low bandwidth environments• Maintainable structure• Testability
Fundamentals
• JavaScript and CSS separated from markup• Script reads and enhances markup• Presentational markup injected by script
dowebsitesneedtolookexactlythesameineverybrowser.com
Don’t Break The Web!
<a href="/foo”
onclick="return doSomething()">
Click me
</a>
Markup:<a href="/foo" class="profile">Click me</a>
External script file:$('a.profile').click(doSomething);
Separation of markup & behaviour
<a href="/foo" class="popup">Click me</a>
$('a.popup').click(function() {
displayInPopup('/foo');
return false;
});
<a href="/foo" class="popup">Click me</a>
$('a.popup').click(function() {
displayInPopup($(this).attr('href'));
return false;
});
Read and enhance markup
EXAMPLEForm enhancements and dialogs
The X-Ray Perspective
1. Map design components to basic HTML2. Build markup with simple styles & no JS3. Layer visual & interaction enhancements
using JS & CSS
EXAMPLEData visualisation
How can Grails help?
request.xhr• different response for AJAX requests• render template / view• disable SiteMesh• forward rather than redirectwithFormat• respond with different data typesWebUtils.isIncludeRequest• tailor response for full page or content section
Varying output for AJAX
def show = {
def model = // … whatever
if (request.xhr) {
render template: "basket", model: model
} else {
return model
}
}
Disabling SiteMesh for AJAX
<!doctype html>
<html>
<head>
<g:if test="${!request.xhr}">
<meta name="layout" content="main">
</g:if>
EXAMPLEPagination -> infinite scroll
Test-driven progressive enhancement
Use browser capability detection to…• activate script-driven behaviour• activate 'polyfills' on less capable
browsers• selectively load JavaScript and CSS files• apply advanced CSS rules to capable
browsers
<html class="js flexbox canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop no-websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity no-cssanimations csscolumns cssgradients no-cssreflections csstransforms no-csstransforms3d csstransitions fontface video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">
.dialog {
background-color: #ccc;
}
.rgba .dialog {
background-color: rgba(0, 0, 0, 0.3);
}
if (Modernizr.geolocation) {// use native geolocation
} else {// activate JavaScript polyfill
}
Modernizr
EXAMPLEFOUC prevention
Yepnope.js
yepnope({
test : Modernizr.geolocation,
yep : 'normal.js',
nope : ['polyfill.js', 'wrapper.js’]
});
EXAMPLEAJAX-enhanced pagination
• Build for mobile devices first• Layer up to desktop using media queries• Prevent large images & supplementary
content sections loading
body { background: url(low-res-image.png);}
@media screen and (min-width: 480px) { body { background: url(hi-res-image.png); max-width: 1140px; } #main, #sidebar { float: left; } #main { width: 65%; } #sidebar { width: 35%; }}
Mobile-first progressive enhancement
What to avoid in Grails
AJAX tags:• g:formRemote
• g:remoteField
• g:remoteFunction
• g:remoteLink
Resources plugin & templates
<r:use module="div-enhance-script"/>
• Useful for highly modular apps• Script included at end of page• Can be used multiple times & script is
only included once
Resources plugin & yepnope.js
<r:script disposition="head">
yepnope({
test : Modernizr.geolocation,
yep : "${r.resource(uri: 'normal.js')}",
nope : [
"${r.resource(uri: 'polyfill.js')}",
"${r.resource(uri: 'wrapper.js')}"
]
});
</r:script>
Thank you!
@rfletcherEW
adhockery.blogspot.com
www.energizedwork.com