Get started with using GWT-friendly CSS media queries and multi-device layout patterns to develop mobile-responsive web applications. Demonstrations are based on an open source code base that you can use as a foundation for your own responsive navigation menus, dialogs, and more.
Building a modern online application without mobile-platform support is like running a fast-food chain without the drive-thru. A web-only strategy will cost you half or more of your potential visitors. On the other hand, imagine building a drive-thru with an entrance for every kind of car. That scenario would be absurd in the brick-and-mortar world, but it is exactly what the native approach to mobile application development entails. Writing for multiple code bases and environments and providing relevant support, bug fixes, and releases for them all is a well-paved road to programmer hell.
That is why it's no surprise that responsive web design has emerged as a popular approach to supporting web applications on mobile devices. Responsive design frees you from worrying about how the application will run on a specific platform. Instead, the application is written to adapt to different environments by adjusting its layout for a given screen size.
In this article we introduce some techniques of web responsive design, using a live mobile-responsive web application as our proof of concept. The CuppaFame application was built using GWT (Google Web Toolkit). In addition we provide a dedicated collection of open source foundation libraries (gwt-responsive
) that you can use to explore or build your own similarly responsive web project.
Simulating mobile environments in a web browser
Responsive web design starts in the application design and implementation phase, when we use tools to simulate different platforms and screen sizes. Some of these tools can be accessed from your browser. For instance, Firefox has a Responsive Design View tool that will simulate any screen size, as well as mobile-device operations like screen rotation and touch events. Chrome Developer Tools goes several steps further with its Toggle feature, which lets you play with views for most mobile devices in the browser.
Figure 1 demonstrates the front page of the original web version of CuppaFame. We are looking at it in full-screen mode. The header at the top of the page allows us to search for various types of documents. The menu panel on the right lets users save search queries, place documents in public or private folders, create and update a user profile, and interact through social networks.
This layout looks fine in a desktop browser but how will it look on a smartphone screen? We can use Firefox's Responsive Design View to see how the layout would look on a particular device. Open the SAVED FOLDERS tab in the topic menu on the left side of your Firefox Responsive Design View screen. Then open Folders Examples and choose the CuppaFame Collage folder. You are now looking at a screenshot of Thomas A. Edison's patent for the Electric Lamp! The screen captures below show the screen as the user would see it rendered for an iPhone 5 device.
This is responsive design in action. Since the application cannot display the whole screen on the iPhone 5 device, it instead lets the user toggle between two modes: Menu and Content. This is only one example of what we can do with responsive web design and development, but it's a place to start. Next we'll set up the project and look at some code.
Building and running a responsive web application
We're using an open source Maven project to illustrate our major points about responsive web design. You can also use this project as a foundation for your own applications. Because the project is pure Maven you will be spared from having to download and configure Google Plugin and other components.
The instructions below will guide you through setting up the project so that you can run it from your command-line or Eclipse environment, which allows debugging. Alternatively, you could access the project online to see the functionality as it is implemented live.
Maven setup
- Download Apache Maven from the Maven project page.
- Configure your system/user path to point to the maven home directory:
*\apache-maven\bin
. - Make sure the
JAVA_HOME
environment variable points to your JDK (version 1.7x in our example). - Download the open source foundation project, gwt-responsive, into a new project directory.
- From the command-line go to your new
gwt-responsive
project directory and run the command:mvn gwt:run
. This will launch GWT Dev Mode: - Clicking Launch Default Browser will open the application in your web browser:
Optional: Building and running a responsive example project in Eclipse
If you would like to build and run the project in Eclipse (and not just run it from the command-line), take the following steps:
- Download the gwt-responsive project source code from its GitHub repository:
- Import this code into your Eclipse environment as an Existing Maven project:
- Find the
pom.xml
file in your Eclipse project and right-click on it. Select the Run As and Maven Install menu items to install all the necessary project components. You will receive the console message "BUILD SUCCESS
" when the application is ready to run:
As our last step in the setup process, let's set up the application for debugging.
- Right-click on your
pom.xml
file again, then select Debug As followed by Maven Build. - In the edit configuration and launch window set the goals value as
gwt:debug
and click the Debug button. You should be able to see the console message: "Listening for transport dt_socket at address: 8000
": - Next we need to add a new remote Java application configuration. Right-click on the
pom.xml
, then select the following path: Debug As-->Debug Configurations-->Remote Java Application-->New Launch Configuration. You will see the console message “java application running on host: localhost port:8000
". - Once again you will see the GWT Development Mode screen. Click the Launch Default Browser button to run and debug the application in your browser.
Architecture of the example project
The CuppaFame example project is built using gwt-platform (GWTP), an open source model-view-presenter (MVP) framework for GWT.
The project has eight major modules. Each module is a classic MVP component responsible for a specific feature of the application's user interface (UI) functionality. MVP views are defined by view classes and corresponding UI binder files, which are designated *.ui.xml
. The UI binders define the HTML layout for each module.
GWTP application modules
The application modules are as follows:
- Main client application (
*.client.application
) houses all of the application modules. - Main menu (
*.client.application
) is in charge of menu items and their functionality. - About (
*.client.application.about
) is responsible for displaying the application's About page. - Home (
*.client.application.home
) is in charge of the application's homepage. - Record View (
*.client.application.complex
) implements the record-view page. - Login Dialog (
*.client.application.login
) demonstrates dialog usage. - GIN (GWT INjection) (
*.client.application.gin
) is the project's dependency injection framework. We also use Guice (*.server.guice
) to glue together the application components on the server side. - Resources modules (
*.client.resources.css
and*client.resourses.css
) house the responsive features of our application, enabling it to adjusts its layout for any mobile screen.
Now that we've set up the application and toured its basic components, we are ready to look at the implementation details of the toggle feature. Toggling between layouts is just one element of responsive design for smaller screens, but this example lets us explore various techniques and patterns of responsive design in GWT.
Loading and controlling mobile style sheets and resources in GWT
A major objective of this project is to avoid heavy JavaScript coding. We can achieve this goal quite gracefully by using resources and style sheets in GWT. Listing 1 shows the *.client.resources.MainResources.java
interface, where we have defined two style-sheet resources.
Listing 1. MainResources.java
@Source("css/Main.css") // css is a general stylesheet
MainStyles css();
@Source("css/Mobile.css") // mobile stylesheet is in charge of mobile platform rendering
TextResource mobile();
Resource Loader class (*.client.gin.ResourceLoader.java) // is in charge of loading our resources as described above:
public class ResourceLoader {
@Inject
ResourceLoader(MainResources resources) {
resources.css().ensureInjected();
String mobileCss = resources.mobile().getText();
StyleInjector.injectAtEnd(mobileCss); // inject css content at the end of head element
}
GWT doesn't support media style sheets directly, so we need to find a way to bypass this restriction. In this case our workaround is to inject the string with media CSS content at the end of the head DOM element.
This approach uses main.css
classes by default, replacing their properties with ones defined in mobile.css
for screens of smaller dimensions. For our implementation we used CSS media queries. For example, mobile.css
contains the media query: @media all and (max-width: 800px) {...}
. When the device screen width is less than or equal to 800 pixels, the properties of the main CSS will be replaced with values defined by this query.
Note that in order for this technique to work, we need to make sure that GWT doesn't obfuscate the names of the CSS classes. You can turn off obfuscation by defining all CSS classes with the declaration @external
in the main.css
resource.
Responsive menu toggling
We have described the basic responsive behavior of enabling a user to switch between the Menu and Content modes on a mobile device screen. Now let's look at the implementation code that enables this behavior.
In Listing 2, the UI binder file ApplicationView.ui.xml
manages our root layout panel. Note that there are three components mainMenuPanel
, centerPanel
, and northSlot
but only northSlot
contains a toggleMenu
button.
Listing 2. ApplicationView.ui.xml
<g:FlowPanel ui:field="scrollPanel" addStyleNames="{res.css.mainScrollPanel}">
<g:FlowPanel ui:field="mainMenuContainer" addStyleNames="{res.css.mainMenuContainer}">
<g:FlowPanel ui:field="mainMenuPanel" addStyleNames="{res.css.mainMenu}" />
</g:FlowPanel>
<g:FlowPanel ui:field="centerContainer" addStyleNames="{res.css.mainPlaceContainer}">
<g:SimplePanel ui:field="centerPanel" />
</g:FlowPanel>
// contrary to intuition, northSlot should be after center because
the center will go under the north (fixed) while scrolled //
<g:SimplePanel ui:field="northSlot" addStyleNames="{res.css.mainNorthPanel}">
<g:HorizontalPanel>
<g:cell horizontalAlignment="ALIGN_LEFT" width="24px">
<g:ToggleButton ui:field="toggleMenu">
<g:upFace image="{res.mainMenu24px}"/>
<g:downFace image="{res.mainMenu24px}"/>
</g:ToggleButton>
</g:cell>
<g:cell verticalAlignment="ALIGN_MIDDLE" horizontalAlignment="ALIGN_RIGHT" width="100%">
<g:Anchor ui:field="login" text="{msg.login}" addStyleNames="{res.css.login}"/>
</g:cell>
</g:HorizontalPanel>
</g:SimplePanel>
</g:FlowPanel>
Our objective is to display the toggleMenu
button only on screens of 800 pixels or less. Clicking on this button should enable the user to toggle between the UI's Content and Menu modes by hiding and showing mainMenuPanel
. The Toggle button in CSS is named mainMenuToggler
; it is defined as invisible in the main.css
class:
@external .mainMenuToggler ;
.mainMenuToggler {
display: none;
vertical-align: bottom;
}
The mobile.css
stylesheet makes sure that this button is displayed on mobile screens of 800 pixels or less by replacing the value of the display
property, as shown here:
@media all and (max-width: 800px) {
.mainMenuToggler {
display: inline-block;
}
Using CSS selector for GWT interaction with the UI
Next we need to be able to intercept the click event associated with the Toggle button, instructing it to hide or show a given menu panel based on the button's state. For this to work, we first need to be able to save the current state of menu visibility, which could be on or off. The CSS selector technique fits this purpose perfectly. Listing 3 shows the relevant fragments from mobile.css
.
Listing 3. CSS selector in mobile.css
@media all and (max-width: 800px) {
…
.mainRootPanel[menu="off"] .mainMenuContainer {
margin-left: -100%;
}
.mainRootPanel[menu="on"] .mainMenuContainer {
margin-left: 0px;
}
This code defines the layout of the mainMenuContainer
that should be hidden or shown depending on the Toggle button's state. Note that the menu panel has a margin-left
CSS property. It is set up dynamically depending on the attribute menu
. If the value is off
the panel is invisible. In a Java implementation we would set up this attribute to respond to the Toggle button's state. In the code below ApplicationView.java
intercepts a click event:
toggleMenu.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
rootPanel.getElement().setAttribute("menu", event.getValue() ? "on" : "off");
...
}