Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solve Media Query verbosity/repetition with MQ variables (new proposal) #64

Closed
kornelski opened this issue Sep 12, 2013 · 8 comments
Closed

Comments

@kornelski
Copy link

Authors often define media query "breakpoints" for small/medium/large layouts (preferrably named), and hate repeating those media queries all over the place, especially in many places in the HTML markup for <source>.

Use of breakpoint-specific media query in <source> is a maintenance work if author decides to change the breakpoints (HTML templating could help a bit, HTML and CSS use different preprocessors, so there's still mix of syntaxes and technologies).

I propose solving this by introducing Media Query Variables. This solves verbosity problem not only for picture, but for breakpoints everywhere in general.

CSS Variables with cascade/inheritance can't be used for MQs, because cascade and inheritance is calculated after media queries. However, a similar, familiar syntax can be used for media query variables.

You define a Media Query Variable (breakpoint name) at the top of a stylesheet with @var-media:

@var-media breakpoint-name: (min-width:etc) and (whatever-you-like:etc);

(note there's no {}, this only defines that a name is equal to a query).

To use the variable you use var(name) in the place where you'd use the full media query:

  @media var(breakpoint-name) { ...CSS goes here as usual... }

For example if you define this in CSS (I recommend in <style> element in <head>, more on that later):

   @var-media small-touchscreen: screen and (max-device-width: 480px) and (pointer: coarse);

Then you can use images specifically for this breakpoint like this:

    <picture>
        <source media="var(small-touchscreen)" src="tap.png">
        <source src="click.png">
    </picture>

and it works just as if it was:

    <picture>
        <source media="screen and (max-device-width: 480px) and (pointer: coarse)" src="tap.png">
        <source src="click.png">
    </picture>

I think @srcset could also be changed from weird w/h syntax to use MQ variables.

Bigger example:

<!DOCTYPE html>
<head>
<style>
    /* @var-media <name of the variable>: <media query>; */

    @var-media smalltouchscreen: screen and (max-device-width: 480px) and (pointer: coarse);
</style>
<style>

/* var(<name of mq variable>) is equivalent to using full MQ in its place */

@media var(smalltouchscreen) {
}

/* thanks to the definition at the top is now same as: */

@media screen and (max-device-width: 480px) and (pointer: coarse) {
}
</style>
<link rel=stylesheet href="…"><!-- can use @media var(smalltouchscreen) too -->
</head>
<body>
    <!-- 
    <img srcset="<file> <1x/2x/etc optional> <media query optional>" 
    -->
    <img srcset="tap-lowres.png var(smalltouchscreen), tap-hires.png 2x var(smalltouchscreen), click-hires.png 2x, click.png"/>
    <img srcset="click.png screen, pencil-and-fax-back.eps print"/>

    <picture>
        <source media="var(smalltouchscreen)" src="tap.png">
        <source src="click.png">
    </picture>
</body>

CSS vs Preload Scanner

Browsers want to start downloading images before external CSS is loaded, and before layout is computed. Therefore solutions that depend on layout or cascaded/inherited CSS properties on elements are disqualified.

Luckily MQ variables don't use inheritance and don't depend on layout. If they're put in <style> in <head> it will be possible to interpret them without waiting for external CSS or layout (authors who can't edit <head> can still use full MQs in <picture>).

I'm sure there will be some grimacing about parsing CSS in the preload scanner, but just extracting @var-media rules from top of the stylesheet is very easy (I'll write the few lines of parser code for browser vendors who complain it's too hard).

Having MQ variables in <head> rather than external file isn't ideal for authors, but it's the best compromise that can be done for maintainability without discarding the preload scanner.

Variables that are not (yet) defined don't match anything. This gives nice feature at zero extra implementation cost: If @var-media definitions are put in an external CSS file and all <source> alternatives use a MQ variable, then <picture> wouldn't load anything until external CSS file is loaded (this is good — it's a bit like lazyload/postpone and avoids double-loading by preload scanner).

This way authors have a choice of having decent maintainability and good performance by inlining <style> with MQ definitions, or putting definitions in an external CSS file only at cost of losing preload scanner (which may be reasonable in a JS app without progressive enhancement, because it can't benefit from preload scanner already).

@yoavweiss
Copy link
Member

@Kornel - I 100% agree with you that this is necessary, but this issue is not specific to the picture element. I've started a thread on the CSSWG mailing list, where the use-case was taken seriously.

From informal talks with members of the CSSWG I understood that there is work going on in that aspect.

@kornelski
Copy link
Author

Indeed, I've just started it here, because verbosity has been stated as one of main problems with <picture> and maintenance of breakpoints is a problem for both <picture> and @srcset, so they're top "users" of this feature :)

@anselmh
Copy link
Member

anselmh commented Sep 12, 2013

I would go even further on your proposal to provide not only media-query variables but more something like html-variables / document-variables which I can set for basically everything that can be written in a html-file.
There are a lot more use-cases for that but you're definitely right to say picture is a heavy-user for that.

@kornelski
Copy link
Author

@dkeeghan
Copy link

I wouldn't mind seeing SCSS syntax for variable declarations, pretty simply it's just:

$small-touchscreen: screen and (max-device-width: 480px) and (pointer: coarse);

which is used like:

@media $small-touchscreen {

}

You could also then:
<img srcset="tap-lowres.png $small-touchscreen, tap-hires.png 2x $small-touchscreen, click-hires.png 2x, click.png"/>

Seems neater and less markup required.

@kornelski
Copy link
Author

@dkeeghan that would be cool if cascading variables used the same syntax: http://dev.w3.org/csswg/css-variables/#using-variables

I'm suggesting @var-media prefix to make it clear that these are MQ-only variables, and it wouldn't make sense to do something like background-color: $small-screen (instead you wrap it in @media var(small-screen) {})

@dkeeghan
Copy link

@pornel ah makes sense now, I hadn't heard about cascading variables, are these new? (I notice the doc is only 3 days old)

@yoavweiss
Copy link
Member

This is an important issue to solve IMO, but out of scope of the <picture> element. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants