407

I need to dynamically load banner images into a HTML5 app and would like a couple of different versions to suit the screen widths. I can't correctly determine the phone's screen width, so the only way I can think of doing this is to add background images of a div and use @media to determine the screen width and display the correct image.

For example:

 <span style="background-image:particular_ad.png; @media (max-width:300px){background-image:particular_ad_small.png;}"></span>

Is this possible, or does anyone have any other suggestions?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Dancer
  • 17,035
  • 38
  • 129
  • 206
  • 6
    Disappointed with the answers? See [this comment](https://stackoverflow.com/questions/9808233/is-it-possible-to-put-css-media-rules-inline#comment49363541_9808297). It may help. – rinogo Aug 04 '18 at 02:57
  • 2023: For the OP's original issue (dynamically swapping image assets), use the `` element, which is way more clean/elegant. Inline media queries, if possible, would be nice although would serve other use cases. – Kalnode Apr 19 '23 at 12:51
  • if working on a .cshtml file, razor view engine will raise errors for the @ character. to bypass razor, simply use double @@, for example "@@media print { html, body { height: 99% !important; } }" – Emre Bener Jul 14 '23 at 06:49

14 Answers14

366

@media at-rules and media queries cannot exist in inline style attributes as they can only contain property: value declarations. As the spec puts it:

The value of the style attribute must match the syntax of the contents of a CSS declaration block

The only way to apply styles to one specific element only in certain media is with a separate rule in your stylesheet (be it linked externally or internally in a <style> element), which means you'll need to come up with a selector for it. You can grab one using your browser's dev tools, or figure out a class and/or ID combination that isolates this element:

#myelement { background-image: url(particular_ad.png); }

@media (max-width: 300px) {
    #myelement { background-image: url(particular_ad_small.png); }
}

If you're unable to find a selector that will reliably match this element alone due to the nature of your page, you can use a custom property, provided you don't need to worry about specificity or Internet Explorer:

:root { --particular-ad: url(particular_ad.png); }

@media (max-width: 300px) {
    :root { --particular-ad: url(particular_ad_small.png); }
}
<span style="background-image: var(--particular-ad);"></span>
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 89
    You can also just put in a ` – Jake Wilson Jun 04 '15 at 17:13
  • 2
    @Jakobud: Yeah, it doesn't matter where the stylesheet is located but the point is that you can only do this in CSS, not an inline style attribute. – BoltClock Jun 04 '15 at 17:14
  • 10
    Note to future explorers that the ` – TCannadySF Nov 16 '16 at 19:15
  • 3
    Don't forget to set max-width in `em`s, not in `px`. That way it will still work sensibly when you zoom. – Silas S. Brown Jun 30 '17 at 12:21
  • Oddly, the [declaration list](https://www.w3.org/TR/css-syntax-3/#declaration-list-diagram) railroad diagram shows that at rules can appear in declaration lists. – Mike Samuel May 20 '19 at 18:58
  • 2
    @Mike Samuel: I believe that was originally there to account for `@page` at-rules. Today the css-nesting spec takes full advantage of this with the [`@nest` at-rule](https://drafts.csswg.org/css-nesting-1/#at-nest). – BoltClock Sep 01 '19 at 18:37
171

Problem

No, Media Queries cannot be used in this way

<span style="@media (...) { ... }"></span>

Solution

But if you want provided a specific behavior usable on the fly AND responsive, you can use the style markup and not the attribute.

e.i.

<style scoped>
.on-the-fly-behavior {
    background-image: url('particular_ad.png'); 
}
@media (max-width: 300px) {
    .on-the-fly-behavior {
        background-image: url('particular_ad_small.png');
    }
}
</style>
<span class="on-the-fly-behavior"></span>

See the code working in live on CodePen

In my Blog for example, I inject a <style> markup in <head> just after <link> declaration for CSS and it's contain the content of a textarea provided beside of real content textarea for create extra-class on the fly when I wrote an artitle.

Note : the scoped attribute is a part of HTML5 specification. If you do not use it, the validator will blame you but browsers currently not support the real purpose : scoped the content of <style> only on immediatly parent element and that element's child elements. Scoped is not mandatory if the <style> element is in <head> markup.


UPDATE: I advice to always use rules in the mobile first way so previous code should be:

<style scoped>
/* 0 to 299 */
.on-the-fly-behavior {
    background-image: url('particular_ad_small.png'); 
}
/* 300 to X */
@media (min-width: 300px) { /* or 301 if you want really the same as previously.  */
    .on-the-fly-behavior {   
        background-image: url('particular_ad.png');
    }
}
</style>
<span class="on-the-fly-behavior"></span>
Bruno J. S. Lesieur
  • 3,612
  • 2
  • 21
  • 25
  • 11
    This is a better answer than the accepted answer because it allows you to dynamically change the `background-image` when the page loads. – Jake Wilson Jun 04 '15 at 17:15
  • I like this answer, too bad support for scoped is currently very limited. – laughingpine Jun 11 '15 at 23:07
  • 8
    While scoped seems great in principle, Chrome removed their preliminary support a few versions back and now only Firefox has any support whatsoever. – Anthony McLin Jul 10 '15 at 02:36
  • 1
    Scoped is just used to not allow `.on-the-fly-behavior` to be used anywere but if the word is « ignore » by some navigator is not a problem. – Bruno J. S. Lesieur Nov 14 '15 at 15:50
  • 4
    Although `scoped` is a brilliant solution it is not officially supported by any browser. Hopefully that will change soon. – Ken Sharp Feb 16 '16 at 00:19
  • according to https://www.campaignmonitor.com/css/b/ separate style tags are not supported in Gmail. do you have any suggestion about how to use media queries in html emails? – omid.n Mar 11 '16 at 11:41
  • 2
    This is an other question, because the main goal of an Email is to be reading by a Client Email and many Client Email do not support embedding ` – Bruno J. S. Lesieur Mar 11 '16 at 13:00
  • 11
    Guys, don't use "scoped" on – Vlad Oct 31 '19 at 08:20
  • Didn't `scoped` depreciate? https://github.com/whatwg/html/issues/552 – Hassan Khan May 19 '22 at 14:08
17

Yes, you can write media query in inline-css if you are using a picture tag. For different device sizes you can get different images.

<picture>
    <source media="(min-width: 650px)" srcset="img_pink_flowers.jpg">
    <source media="(min-width: 465px)" srcset="img_white_flower.jpg">
    <img src="img_orange_flowers.jpg" alt="Flowers" style="width:auto;">
</picture>
JJJ
  • 32,902
  • 20
  • 89
  • 102
Arif Hussain
  • 187
  • 1
  • 2
  • 3
    This does not apply to CSS background-image: url() – Jonas Eberle Sep 04 '19 at 10:39
  • 2
    If I understand well, this does not change the CSS based on viewport size, it changes the picture. So the CSS and layout will still be the same, but the op asked to use CSS media rules. – Max Sep 29 '20 at 18:31
  • IMHO, this should be the top answer and is exactly the solution for the OP's use case: swapping image assets based on viewport conditions. The `` element not has broad browser support. "Inline media queries" happened to takeover the discussion all of these years because at the time, that was presumed the most efficient way (if possible) to achieve this. It would still be nice to have inline @media support, anyhow. – Kalnode Apr 19 '23 at 12:45
16

Inline styles cannot currently contain anything other than declarations (property: value pairs).

You can use style elements with appropriate media attributes in head section of your document.

Marat Tanalin
  • 13,927
  • 1
  • 36
  • 52
9

If you are using Bootstrap Responsive Utilities or similar alternative that allows to hide / show divs depending on the break points, it may be possible to use several elements and show the most appropriate. i.e.

 <span class="hidden-xs" style="background: url(particular_ad.png)"></span>
 <span class="visible-xs" style="background: url(particular_ad_small.png)"></span>
Pavel
  • 107
  • 1
  • 3
  • 3
    Beautiful workaround--hide div, show div based on media query--the only drawback I see is it will still load both images so you'd be sending both to the client. – Michael C. Gates Nov 20 '14 at 13:13
  • 5
    Duplicate content is not a good thing for maintenance or SEO. – Bruno J. S. Lesieur Oct 14 '15 at 12:15
  • 1
    Unfortunately this is a false friend! I thought about this solution too, but we want smaller picture to serve to small devices and to save bytes to download. This technique does exactly the opposite – A. D'Alfonso Jul 14 '17 at 11:36
9

Hey I just wrote it.

Now you can use <div style="color: red; @media (max-width: 200px) { color: green }"> or so.

Enjoy.

8

Media Queries in style-Attributes are not possible right now. But if you have to set this dynamically via Javascript. You could insert that rule via JS aswell.

document.styleSheets[0].insertRule("@media only screen and (max-width : 300px) { span { background-image:particular_ad_small.png; } }","");

This is as if the style was there in the stylesheet. So be aware of specificity.

Type-Style
  • 1,791
  • 1
  • 16
  • 35
7

I tried to test this and it did not seem to work but I'm curious why Apple is using it. I was just on https://linkmaker.itunes.apple.com/us/ and noticed in the generated code it provides if you select the 'Large Button' radio button, they are using an inline media query.

<a href="#" 
    target="itunes_store" 
    style="
        display:inline-block;
        overflow:hidden;
        background:url(#.png) no-repeat;
        width:135px;
        height:40px;
        @media only screen{
            background-image:url(#);
        }
"></a>

note: added line-breaks for readability, original generated code is minified

davidcondrey
  • 34,416
  • 17
  • 114
  • 136
  • 4
    I would like to know why/how Apple is using that also – Douglas.Sesar Aug 30 '14 at 19:05
  • 1
    Quoted code no longer exists at the given link (at least for me; perhaps I get different content due to being outside the US). Besides, this really seems more like a separate question that an answer. – Mark Amery Jun 11 '15 at 22:55
  • 2
    I submitted a bug report and I believe they have since removed it. http://itunesaffiliate.phgsupport.com/hc/en-us/requests/14201 – davidcondrey Jun 25 '15 at 04:09
6

A Javascript solution to the OP's specific issue (responsive images), using window.matchMedia:

Demo color codes:

  1. desktop for red colour text
  2. tablet for green colour text
  3. mobile for blue colour text

//isat_style_media_query_for_desktop_mobile_tablets
var tablets = window.matchMedia("(max-width:  768px)");//for tablet devices
var mobiles = window.matchMedia("(max-width: 480px)");//for mobile devices
var desktops = window.matchMedia("(min-width: 992px)");//for desktop devices



isat_find_device_tablets(tablets);//apply style for tablets
isat_find_device_mobile(mobiles);//apply style for mobiles
isat_find_device_desktops(desktops);//apply style for desktops
// isat_find_device_desktops(desktops,tablets,mobiles);// Call listener function at run time
tablets.addListener(isat_find_device_tablets);//listen untill detect tablet screen size
desktops.addListener(isat_find_device_desktops);//listen untill detect desktop screen size
mobiles.addListener(isat_find_device_mobile);//listen untill detect mobile devices
// desktops.addListener(isat_find_device_desktops);

 // Attach listener function on state changes

function isat_find_device_mobile(mob)
{
  
// isat mobile style here
var daynight=document.getElementById("daynight");
daynight.style.color="blue";

// isat mobile style here

}

function isat_find_device_desktops(des)
{

// isat mobile style here

var daynight=document.getElementById("daynight");
daynight.style.color="red";
 
//  isat mobile style here
}

function isat_find_device_tablets(tab)
{

// isat mobile style here
var daynight=document.getElementById("daynight");
daynight.style.color="green";

//  isat mobile style here
}


//isat_style_media_query_for_desktop_mobile_tablets
    <div id="daynight">tricky style for mobile,desktop and tablet</div>
Kalnode
  • 9,386
  • 3
  • 34
  • 62
Balaji
  • 9,657
  • 5
  • 47
  • 47
  • 3
    This is possibly a viable answer but I would not say "yes you can do it" because the OP did not ask for a JavaScript solution and instead was asking for a pure CSS solution. What the OP is wanting to do is not possible, but this is a potential workaround depending on the scenario. – Xandor Aug 12 '20 at 18:28
  • JavaScript cannot be used in email — client support for it is inadvisable and rare: https://stackoverflow.com/q/3054315/211327 – Alan H. Apr 13 '22 at 18:13
  • What happens between 768px and 992px with this code? – Intacto Feb 10 '23 at 13:48
  • Difficult to upvote any "Yes" answer that relies on Javascript. – Kalnode Mar 09 '23 at 14:39
4

You can use image-set()

<div style="
  background-image: url(icon1x.png);
  background-image: -webkit-image-set(  
    url(icon1x.png) 1x,  
    url(icon2x.png) 2x);  
  background-image: image-set(  
    url(icon1x.png) 1x,  
    url(icon2x.png) 2x);">
the7oker
  • 160
  • 2
  • 5
  • 2
    Note that this is [only supported in Webkit-based browsers](http://caniuse.com/#search=image-set) right now. – Qqwy Apr 13 '17 at 09:05
  • This doesn't work based on size (as outlined in the question) but on the zoom factor, so you might get the picture for small screens on a 27“ 2560x1440 screen. That might be what you want - or maybe not. – Jan Bühler Jul 10 '17 at 11:27
  • 2022 update: Nearly universally supported, browser-wise, usually with the `-webkit-` prefix (no prefix in Firefox). Not sure how many email clients will allow this technique (I am almost certain most sanitize CSS to some degree) – Alan H. Apr 13 '22 at 18:16
  • This is good for scaling a single asset, however OP's use case was actually _changing_ assets, which is what the `` element is good for. – Kalnode Apr 19 '23 at 12:39
3

Inline media queries are possible by using something like Breakpoint for Sass

This blog post does a good job explaining how inline media queries are more manageable than separate blocks: There Is No Breakpoint

Related to inline media queries is the idea of "element queries", a few interesting reads are:

  1. Thoughts on Media Queries for Elements
  2. Media Queries are a Hack
  3. Media Queries Are Not The Answer: Element Query Polyfill
  4. if else blocks
rlueder
  • 349
  • 2
  • 6
1

if you add the rule to the print.css file you don't have to use @media.

I uncluded it in the smarty foreach i use to give some elements a background color.

<script type='text/javascript'>
  document.styleSheets[3].insertRule(" #caldiv_<?smarty $item.calendar_id ?> { border-color:<?smarty $item.color ?> }", 1);
</script>
1

It's crazy they didn't think of media queries at HTML level, as obviously style css gets loaded after html, it's a huge disadvantage to inlining style inside html.

AGrush
  • 1,107
  • 13
  • 32
-2

Yes, this is quite possible but only as using javascript event attributes in HTML elements. Here you have to keep in mind that not every html tag element could fire every js event, which can listen for changes to the DOM, such as onresize or execute js code, when DOM is loaded, as onload event does. In the example above I use body and img tags as they are capable to fire img only onload event, body tag both onload and onresize. Depending on the event, you could choose the approach to resolve your issue, as using the code from the examples.

Using a body tag:

<body onload="
const mediaQueryList = window.matchMedia('(max-width: 600px)');
function screenTest(e) {
 if (e.matches) {
 /* the viewport is 600 pixels wide or less */
  console.log('This is a narrow screen — 600px wide or less.');
  document.body.style.backgroundColor = 'pink';
 } else {
 /* the viewport is more than 600 pixels wide */
  console.log('This is a wide screen — more than 600px wide.');
  document.body.style.backgroundColor = 'aquamarine';
 }
}
mediaQueryList.addEventListener('change', screenTest);
" onresize="
if (document.documentElement.offsetWidth <= 600) {
/* the viewport is 600 pixels wide or less */
console.log('This is a narrow screen — 600px wide or less.');
document.body.style.backgroundColor = 'pink';
} else {
/* the viewport is more than 600 pixels wide */
 console.log('This is a wide screen — more than 600px wide.');
 document.body.style.backgroundColor = 'aquamarine';
}
"><!-- Some other code goes here --></body>

Using img tag:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" 
width="100%" style="width: 100vw; height: 1px;" 
alt="" height="1"  
onload="
   const mediaQueryList = window.matchMedia('(max-width: 600px)');
   function screenTest(e) {
     if (e.matches) {
        /* the viewport is 600 pixels wide or less */
        console.log('This is a narrow screen — 600px wide or less.');
        document.body.style.backgroundColor = 'pink';
     } else {
        /* the viewport is more than 600 pixels wide */
        console.log('This is a wide screen — more than 600px wide.');
        document.body.style.backgroundColor = 'aquamarine';
     }
   }
   mediaQueryList.addEventListener('change', screenTest);
" />

You should also keep in mind that if you decide to use this way of embedding mediaquery css in an HTML letter, it may not pass through the blacklists of mail servers, which in most cases cut such javascript events. But for the purposes of some ajax or banner, some dynamic application, this approach should face no problem.

Christiyan
  • 485
  • 5
  • 5