ADF-WebCenter Responsive-Adaptive Design Beyond

Introduction

A topic that comes up frequently in many ATEAM customer engagements is what are the best practices for producing a responsive design for a WebCenter application. There are many informative blogs and presentations on how to achieve this through-out the web. The methodology and strategies used by the authors will often depend on the how the overall content is to appear based on the size (width) of the screen view port.  These strategies will work with traditional HTML/HTM5. However, the challenges to achieve the same results when developing with ADF may not be straight forward.  The goal of this blog is not to present the methodology. But, rather to introduce design concepts and strategies, which can help you make viable decisions on how to use ADF in a responsive container.

Main Article

You may have noticed that I used the word container in the previous sentence. This is because in the world of sizing ADF components, it is all about the (parent or child) container that the components are within.  Many ADF components (e.g. af:table) are built to stretch based upon the given area of it’s (layout) container.  Because of this inherent behavior and ADF is mostly a declarative by nature, responsive design with ADF is really adaptive design. The strategy then becomes on how to change the ADF component at two levels: CSS – through the component’s style selector and/or by the virtue of its declarative properties. These properties (e.g. Visible) are the attributes, which are typically exposed in the Property View. Before getting into the heart of describing how to achieve this main adaptive strategy, there are a few related concepts that we will cover that can also help determine additional design strategies as well.

Responsive Design Fundamentals

Different Screen Sizes

Responsive Design essentially makes for a better user experience on a wider range of devices.  A Responsive web-site will automatically adjust, or respond, to suit a device’s screen size and orientation. Large or small – landscape or portrait, a responsive site will switch between these on-the-fly.

Adaptive Layouts

The layout of a responsive website design should change to accommodate the type of device that the website will be viewed.  For example, on a desktop view, a large menu bar can be displayed with support for drop down items for the sub menu items. However, on a smartphone, that same menu is displayed as a much more simpler drop down to accommodate for the smaller screen.  In addition, the page will have enumerated break-points, which are reliant on the devices window size.

Items to Consider in a Responsive Design

Start Small

The best approach in designing your over all web site is to design against the smallest view port.  This typically means designing for smaller touchscreens (e.g. mobile) first, then scaling up from there. The majority of the layouts used here will be of a single column type design.  Content items will typically flow from top to bottom and capabilities (i.e. features) will be supported by such items as side panels and/or drawers. The important concept to know when designing small is that even at the most smallest/narrowest view port, the web site should not be necessarily the least capable.

Scaling up

Once the web site has met the needs of mobile users, the focus of the next designs will be for the larger devices  (i.e. tablet, desktops).  There are many strategies that can be viable here: moving content from drawer to a side panel or converting a vertical disclosing menu to a list of horizontal links. This is a technique called re-articulation. The important point is that content always remains accessible to the user at all display widths.

It is considered a bad design practice to completely remove content as the page responds to a change in browser display width. This is referred to as content disparity.

Progressive enhancements are often used as a method to enable the capabilities (i.e. features). These progressive enhancements also can based on browser, device or possible feature detection.  In some instances, JavaScript frameworks like Modernizr and jQuery may also be part of the development process. However, these frameworks can have an ill effect with some ADF components, so be cautious when using these frameworks.

Adaptive Design with ADF

Ethan Marcotte wrote the definitive article on Responsive Web Design.  In this article Ethan embodied his ideas into a single coherent  methodology for Responsive Web Design using these tools: fluid layouts, scalable images, and CSS media queries.  On the other hand, Adaptive design is a technique for implementing responsive design; this technique is best suited for ADF.

The following are screenshots of my example displayed (in pixel widths) from small to large: 480, 768, 1024 and 1250.

Starting at the smallest size, the layout design is incorporating the typical one columns approach. Notice that all content items flow to the size of the view port.

480redone

Increasing the view port width to 768px provides one major change to the layout design: the two sidebars have been repositioned to the right of the Content. This change was implemented by using CSS and a CSS3 media query.  CSS3 media queries will be discussed later in this blog.

768redone

At 1024 pixel width, the content section adapts to the now larger real estate that it inhabits: the two (content) paragraphs has shifted from vertical to horizontal alignment, and the table is displaying two additional columns. In addition, the (pricing) information that was contained in first column is now located in the two new columns.  Both of these ADF adaptation changes are a result of the JavaScript based implementation, which will be discussed later in this blog.

1024redone

At the largest view port (1250px), the column based structure in the design can be clearly observed.

respdes_1250

This overall design is a typical pattern. There is a header, navigation, (main content), side bars, and a footer sections. Although there are noticeable differences of the presentation based on the the view port width, the re-articulation concept is still in effect. In summary, this is a simple design layout and it was achieved by:

  • Parent containers that promote fluidity (no stretching components – i.e. af:panelStretchLayout, af:panelSplitter, .etc).  In this sample, I only used  af:panelGroupLayout (set to vertical), which turns into a HTML DIV.
  • CSS3 Media Queries
  • Custom JavaScript

When declaring CSS elements, such as width, use percentages.  You can use the responsive web design formula: (target/context) x 100 = result%.  For example, if the outer container (OC) is 960 (px) and the desired inner container (IC) is 900 (px).  Then OC set-to-960-width = 100%, so IC width is (900/960) x 100 = 93.75%.  In addition, use em, which is a scalable unit for font sizes.

Parent Containers

Separate containers are included in both the ADF Page Template and for the page that uses the template.  These containers serve as the adaptable regions for each section (i.e. Header, .etc).  An af:facetRef was used to enable the addition of content within regions of the page template. Each (section) af:panelGroupLayout (PGL) is also tagged with a distinct CSS Style class in the PGL property view.  These style classes are used in the media queries.

respdes_1

CSS3 Media Queries

Media queries are an important piece for implementation of a responsive design.  Without media queries, fluid layouts would struggle to adapt to the array of possible screen sizes on hundreds of devices.  For example, fluid layouts can appear to be cramped and basically unreadable on really small mobile devices and on the other hand, render too large on bigger screen devices. Media queries are supported on most modern browsers.  For those browsers (and older versions of Internet Explorer), there are JavaScript based polyfill’s to provide similar support.

Polyfills allow fixing issues with a browser’s API or adding interfaces that haven’t been implemented at all. A polyfill is a shim for a browser API. Typically, a developer will programmatically check if a browser supports an API and will load a polyfill if the API is absent. This allows development to proceed as if the API was native to the browser.

For my example, the following is a snippet of one of the media queries:

@media screen and (max-width:480px) {
    .page {
        padding: 0;
    }
    .sidebar1, .sidebar2 {
        width: 100%;
        float: left;
    }
    .content {
        clear: both;
        width: 100%;
    }
}

In the current 11.1.1.7 ADF/WebCenter release, all CSS3 media queries must be included in a separate CSS file and declared through an af:resource.  Any media queries that are included in WebCenter CSS (Skin) file will be stripped out. In this example, the af:resource is declared on the page template.  This will ensure that any page that uses the template will also have support for the media queries.

JavaScript

For container adaptability management, media queries are often sufficient.  However, for the ADF framework, there are only two ways that adaptability can be achieved. One way is to use JavaScript to manipulate the ADF components directly. ADF Faces expose public JavaScript APIs that can be used to implement client side development.   A white paper is available that discusses this topic can be found here.

Another approach that can be implemented is to manipulate ADF’s declarative based properties by using Expression Language (EL).  For seasoned ADF developers, this is nothing new.  This pattern is used primarily for partial-page-rendering (PPR) type events.  However, this approach also means that the main trigger is a ADF server-side event (unlike the CSS media query and JavaScript that is client side).  The following is an example that will use a combination of JavaScript, Java and EL to enable the adaptation of the af:table.

First the JavaScript part.

function load() {
    console.log('load');
    var listener = new ResizeListener();
    if (listener._matchMediaQueryList) {
        listener._handleChange(listener._matchMediaQueryList);
    }
}

function ResizeListener() {
    console.log('ResizeListener()');
    this.Init();
}

AdfObject.createSubclass(ResizeListener, AdfObject);

ResizeListener.prototype.Init = function () {
    console.log('ResizeListener()');
    this._matchMediaQueryList = window.matchMedia("screen and (max-width:768px)");
    this._matchMediaQueryList.addListener(this._handleChange);
}

ResizeListener.prototype._handleChange = function (_matchMediaQueryList) {
    var document = AdfPage.PAGE.findComponent("d1");

    if (_matchMediaQueryList.matches) {
        AdfCustomEvent.queue(document, "customEvent", {screenSize : 'portrait'}, true);
    }
    else {
        AdfCustomEvent.queue(document, "customEvent", { screenSize : 'landscape' }, true);
    }
}

This is simple code uses the combination of the matchMedia and (assigned) Listener to monitor the screen width. The important piece to understand is when the matchMediaQueryList is matched. When the match is true, an ADF JavaScript API method call is invoked to queue up an ADF based event to the document (page). The event is also passed an parameter screenSize, which can be either big or small. This event is then discovered by the af:serverListener, which has been declared on the page. The serverListener is responsible for executing the custom Java code to: post a flag (screenSize) on the session, then provide a partial target (PPR) to the page.

    public void handleEvent(ClientEvent clientEvent) {
        UIComponent form = clientEvent.getComponent().getChildren().get(1);
        AdfFacesContext afContext = AdfFacesContext.getCurrentInstance();
        String screen =
            clientEvent.getParameters().get("screenSize").toString();
        ADFContext.getCurrent().getSessionScope().put("screenSize", screen);
        afContext.addPartialTarget(form);
    }

The declaration of the JavaScript is on the page template by way of a af:resource tag. However, both the af:serverListener and the af:clientListener (invokes the JavaScript load() on page load), is declared on the page.

The last piece is configure af:table, column property, for example: visible,  to include EL to get the stored session value (e.g. landscape, portrait):

<af:column 
     sortProperty="#{bindings.PlaceholderDataType.hints.Price.name}"
     sortable="false"
     id="c4" noWrap="false"
     visible="#{sessionScope.screenSize == 'landscape' ? 'true' : 'false'}"
     width="40">
     <af:outputText value="#{row.Price}" id="ot2"/>
 </af:column>
<af:panelGroupLayout id="pgl1" layout="#{sessionScope.screenSize == 'landscape' ? 'horizontal' : 'vertical'}">

This same approach is used by this example to switch the layout mode on the af:panelGroupLayout to either horizontal or vertical.  So in summary, for most of the container related items you can use CSS3 based media queries (along with CSS); and to enable the adaptability of the ADF components you can use the JavaScript-to-register a page event approach.  The sample WebCenter (JDeveloper 11.1.1.7) custom application project used for this post is here: ResponsiveDesignBlog.

Conclusion

This blog describes how using both Responsive and Adaptive design patterns can enable WebCenter to support multiple screen view ports. As I mentioned before, there can be other ways on how to get this same support. The following is a list of links that describe these other possibilities:

Comments

  1. vinay kumar says:

    Or is there any way we can use all the components of ADF faces for adaptive design.If using jdeveloper 11.1.1.7 then again we use to use another responsive CSS using af:resources ?? In my case, I am also using custom skin.Don’t that make more complex with custom skinning?

    Whats your thought.I know , now in jdev 12.1.3 media tag it supports in ADF skinning.What you suggst?

  2. vinay kumar says:

    Hello Martin,

    But one disadvantage of using Adaptive design in ADF is , you cant use all the component of ADF faces.You have to stick mainly on panelGroupLayout.
    I am trying to make an ADF application built on jdeveloper 11.1.1.7 then What you suggest. Will this approach will work?

  3. Niranjan Tatiparthi says:

    Thanks Martin for this excellent post

Add Your Comment