CSS @Media queries work arounds?

1,086 views
Skip to first unread message

Ed

unread,
Oct 17, 2013, 6:46:03 AM10/17/13
to google-we...@googlegroups.com
Currently CSS @media queries aren't supported yet in GWT. What are good work arounds?

My list:
1) The css files that contains the @media queries is included a TextResource in your ClientBundle and injected through StyleInjector.inject().

2) The css file doesn't contain @media queries  is included as CssResource in your ClientBundle and injected through StyleInjector.inject() just after the injected string is wrapped in a media query. Example: StyleInjector.inject("@media (max-width: 639px): {" + CSS CONTENT + ");

3) Using the JS window.matchMedia() function to detect and listen to media changes. When the listener is informed, change the injected style by selecting the correct CssResource in your ClientBundle.

4) Add an extra style to the body (or any other root div you use) that represents the current media and use "descendant selectors" in your css  to select the correct style. You can use JS window.matchMedia() function or Window resize listener to detect screen size changes  and change the root style.

5) ??...

The list of pro/cons (that I can intially think of):
1)
Pro: easy and  works 
Con: nasty hack, no use of GWT CssResource functionality like MD5 naming and compiler checks.

2)
Pro: easy and works, and using the GWT CssResource functionality like naming and compiler checks.
Con: nasty hack..

3)
Pro: flexible and works.
Con: Jsni wrapping, risk of memory leaks because of listeners not being cleaned/removed.

4) 
Pro: easy, common, works in older browser.
Con: deep descendant selectors results in less performance.

Refs:
a) Mgwt uses 1).
b) 2) can be found in several js lib's and this gwt post
c) Example code of using 3: linke


Please add your input to the lists?
What do you prefer?

Jens

unread,
Oct 17, 2013, 7:28:13 AM10/17/13
to google-we...@googlegroups.com
The ClientBundle mechanism is pluggable so I would try introducing a new Resource type "MediaQueryAwareCssResource extends CssResource" and try to figure out how well I could reuse the CssResourceGenerator that is responsible for generating the code for normal CssResources. The MediaQueryAwareCssResourceGenerator would probably generate something like 2.) for the ensureInjected() method.

The goal would be

ClientBundle {

  @MediaQuery(width = ..., height = ...)
  MediaQueryAwareCssResource style();

}

-- J.

Ed Bras

unread,
Oct 17, 2013, 7:38:29 AM10/17/13
to google-we...@googlegroups.com
@Jens: but how do you select the correct  "MediaQueryAwareCssResource", and what about switching MediaQueryAwareCssResource when the screen is resized?

Jens

unread,
Oct 17, 2013, 8:00:22 AM10/17/13
to google-we...@googlegroups.com
@Jens: but how do you select the correct  "MediaQueryAwareCssResource", and what about switching MediaQueryAwareCssResource when the screen is resized?


Ok then a bit more:

interface MediaQuery {
  int getWidth();
  String getSource();
}

enum AppMediaQuery implements MediaQuery {
   DESKTOP(<screen size>, "desktop.css"),
   MOBILE(<screen size>, "mobile.css")
}

interface ClientBundle {
  CssResource baseStyle();

  @MediaQuery({AppMediaQuery.DESKTOP, AppMediaQuery.MOBILE})
  MediaQueryCssResource resolutionDependentStyles();
}

When calling resolutionDependentStyles().ensureInjected() it should inject desktop.css and mobile.css with their corresponding media queries.

-- J.

Ed Bras

unread,
Oct 17, 2013, 8:54:28 AM10/17/13
to google-we...@googlegroups.com
I think I currently go for option (4), and I think it will make it easier to upgrade to media queries once supported by GWT

Ed Bras

unread,
Oct 19, 2013, 8:01:56 AM10/19/13
to google-we...@googlegroups.com
I ended up doing the following:
Build  ad tiny jsni wrapper around window.matchMedia() wrapper to detect media changes. I added the wrapper as feature request: issue 8399, including the code.

Detected media changes are pushed to the Facade of the interested app components and they further process them. Note: I push the event change, and not let components pull them through a listeners as that can lead to memory leaks.

I use a central MediaInfo register (singleton) that contains all media info instances such that a component can always retrieve the current media info when it's first shown.

The components can then add/remove widgets/extra styles on a media info change, like a resize. In my case: i have to show a top menu as left menu on smaller devices (like a facebook menu).

Because I needed to detect this change in my app code and not wanted to have duplicated media info in both the app and CSS (and gwt not supporting Css media queries), I have chosen this solution.
An alternative would be to create both a left and top menu and hide/show them through css3 media queries. I don't like this and also created too much unnecessary widgets/components. Note: I am now only talking about a single menu, but more things have to change due to the above media info change.
Reply all
Reply to author
Forward
0 new messages