84

Is it possible to use Javascript inside CSS?

If it is, can you give a simple example?

james.garriss
  • 12,959
  • 7
  • 83
  • 96
  • 4
    Some suggestions below mention Expressions in Internet Explorer - be sure NOT to use these. – Sampson Jan 24 '09 at 16:48
  • 5
    Expressions in IE are evil - they are re-evaluated on every single event (mousemove, anyone?). Therefore, anywhere not-IE they'll silently fail, in IE, they'll slow down the page considerably. – Piskvor left the building Jan 24 '09 at 17:14

7 Answers7

66

IE and Firefox both contain ways to execute JavaScript from CSS. As Paolo mentions, one way in IE is the expression technique, but there's also the more obscure HTC behavior, in which a seperate XML that contains your script is loaded via CSS. A similar technique for Firefox exists, using XBL. These techniques don't exectue JavaScript from CSS directly, but the effect is the same.

HTC with IE

Use a CSS rule like so:

body {
  behavior:url(script.htc);
}

and within that script.htc file have something like:

<PUBLIC:COMPONENT TAGNAME="xss">
   <PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="main()" LITERALCONTENT="false"/>
</PUBLIC:COMPONENT>
<SCRIPT>
   function main() 
   {
     alert("HTC script executed.");
   }
</SCRIPT>

The HTC file executes the main() function on the event ondocumentready (referring to the HTC document's readiness.)

XBL with Firefox

Firefox supports a similar XML-script-executing hack, using XBL.

Use a CSS rule like so:

body {
  -moz-binding: url(script.xml#mycode);
}

and within your script.xml:

<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml">

<binding id="mycode">
  <implementation>
    <constructor>
      alert("XBL script executed.");
    </constructor>
  </implementation>
</binding>

</bindings>

All of the code within the constructor tag will be executed (a good idea to wrap code in a CDATA section.)

In both techniques, the code doesn't execute unless the CSS selector matches an element within the document. By using something like body, it will execute immediately on page load.

Zombo
  • 1
  • 62
  • 391
  • 407
Zach
  • 24,496
  • 9
  • 43
  • 50
  • 7
    (Not sure if asking on a old answer is helpful) I tried the XBL technique in Firefox 18, but it didn't work. Is it only accessible to Firefox extensions? – Sunil Agrawal Dec 31 '12 at 23:52
  • 3
    Also worth noting - HTML components aren't supported in [IE after version 10](http://msdn.microsoft.com/en-us/library/ie/hh801216(v=vs.85).aspx) – Doug Oct 29 '13 at 11:10
  • 6
    As of 2016, XBL [can not](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Tutorial/Using_XBL_from_stylesheets) be loaded via HTTP. – JSmyth Jan 26 '16 at 20:05
  • 1
    @JSmyth what about ꜰᴛᴘ and data ᴜʀɪ ? – user2284570 Jan 09 '19 at 22:59
  • @user2284570 Have not tried it but [this page](https://developer.mozilla.org/en-US/docs/Archive/Beginner_tutorials/Using_XBL_from_stylesheets) says: `Note: XBL cannot be loaded over HTTP, so this technique is only useful for local content accessed using the file:/// scheme, or from add-on code.` I'd be interested to see if you can get it working over data-uri/ftp/etc. This would perhaps mean CORS bypass. – JSmyth Jan 25 '19 at 23:18
  • 1
    Firefox no longer supports XBL and it is being removed from Gecko, as of October 2019: https://bgrins.github.io/xbl-analysis/ – DylanYoung Jun 29 '20 at 20:51
36

I think what you may be thinking of is expressions or "dynamic properties", which are only supported by IE and let you set a property to the result of a javascript expression. Example:

width:expression(document.body.clientWidth > 800? "800px": "auto" );

This code makes IE emulate the max-width property it doesn't support.

All things considered, however, avoid using these. They are a bad, bad thing.

Yogu
  • 9,165
  • 5
  • 37
  • 58
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
6

To facilitate potentially solving your problem given the information you've provided, I'm going to assume you're seeking dynamic CSS. If this is the case, you can use a server-side scripting language to do so. For example (and I absolutely love doing things like this):

styles.css.php:

body
 {
margin: 0px;
font-family: Verdana;
background-color: #cccccc;
background-image: url('<?php
echo 'images/flag_bg/' . $user_country . '.png';
?>');
 }

This would set the background image to whatever was stored in the $user_country variable. This is only one example of dynamic CSS; there are virtually limitless possibilities when combining CSS and server-side code. Another case would be doing something like allowing the user to create a custom theme, storing it in a database, and then using PHP to set various properties, like so:

user_theme.css.php:

body
 {
background-color: <?php echo $user_theme['BG_COLOR']; ?>;
color: <?php echo $user_theme['COLOR']; ?>;
font-family: <?php echo $user_theme['FONT']; ?>;
 }

#panel
 {
font-size: <?php echo $user_theme['FONT_SIZE']; ?>;
background-image: <?php echo $user_theme['PANEL_BG']; ?>;
 }

Once again, though, this is merely an off-the-top-of-the-head example; harnessing the power of dynamic CSS via server-side scripting can lead to some pretty incredible stuff.

Hexagon Theory
  • 43,627
  • 5
  • 26
  • 30
  • 2
    vote up for coolness, but this is server-side. JS is client-side. – DragonLord Sep 07 '12 at 21:30
  • Be sure to enabling caching by sending some headers, otherwise you are unnecessarily slowing down a page load. – Lekensteyn Mar 05 '13 at 14:21
  • This is static. All it does is consume server resources that could be deferred to the client using javascript. –  May 11 '17 at 15:42
2

Not in any conventional sense of the phrase "inside CSS."

Hank Gay
  • 70,339
  • 36
  • 160
  • 222
2

IE supports CSS expressions:

width:expression(document.body.clientWidth > 955 ? "955px": "100%" );

but they are not standard and are not portable across browsers. Avoid them if possible. They are deprecated since IE8.

sastanin
  • 40,473
  • 13
  • 103
  • 130
0

I ran into a similar problem and have developed two standalone tools to accomplish this:

  • CjsSS.js is a Vanilla Javascript tool (so no external dependencies) that supports back to IE6.

  • ngCss is an Angular Module+Filter+Factory (aka: plugin) that supports Angular 1.2+ (so back to IE8)

Both of these tool sets allow you to do this in a STYLE tag or within an external *.css file:

    /*<script src='some.js'></script>
    <script>
        var mainColor = "#cccccc";
    </script>*/

    BODY {
        color: /*{{mainColor}}*/;
    }

And this in your on-page style attributes:

    <div style="color: {{mainColor}}" cjsss="#sourceCSS">blah</div>

or

    <div style="color: {{mainColor}}" ng-css="sourceCSS">blah</div>

NOTE: In ngCss, you could also do $scope.mainColor in place of var mainColor

By default, the Javascript is executed in a sandboxed IFRAME, but since you author your own CSS and host it on your own server (just like your *.js files) then XSS isn't an issue. But the sandbox provides that much more security and peace of mind.

CjsSS.js and ngCss fall somewhere in-between the other tools around to accomplish similar tasks:

  • LESS, SASS and Stylus are all Preprocessors only and require you to learn a new language and mangle your CSS. Basically they extended CSS with new language features. All are also limited to plugins developed for each platform while CjsSS.js and ngCss both allow you to include any Javascript library via <script src='blah.js'></script> straight in your CSS!

  • AbsurdJS saw the same problems and went the exact opposite direction of the Preprocessors above; rather than extending CSS, AbsurdJS created a Javascript library to generate CSS.

CjsSS.js and ngCss took the middle ground; you already know CSS, you already know Javascript, so just let them work together in a simple, intuitive way.

anova01
  • 93
  • 1
  • 10
Campbeln
  • 2,880
  • 3
  • 33
  • 33
  • Hello @Campbeln, your library looks really interesting, and in fact it is just what I was looking for, but I cannot make it to work. Any possibilities for you to help me? – Diego Perez Aug 23 '22 at 11:20
  • For you to have an idea of my goal. I have a css file that starts with a css variable containing the corporative color as follows: :root { --corporativecolor: #00ac50; }, well, I would like that hex color to be set from code behind with vb.net in my asp.net webforms application. I know what I expect is not possible in any traditional way, but thought maybe your library might help me with that. You @anova01? – Diego Perez Aug 23 '22 at 11:23
  • @DiegoPerez you could set it in vb.net, just need to run the file on the server but return with headers for CSS. This library was done long before CSS3's variables were widely available/didn't suck. You can still do a lot with CjsSS, but it's probably a sledge hammer versus a flyswatter. – Campbeln Aug 26 '22 at 05:59
-2

This turns out to be a very interesting question. With over a hundred properties being set, you'd think that you'd be allowed to type .clickable { onclick : "alert('hi!');" ; } in your CSS, and it'd work. It's intuitive, it makes so much sense. This would be amazingly useful in monkey-patching dynamically-generated massive UIs.

The problem:
The CSS police, in their infinite wisdom, have drawn a Chinese wall between presentation and behavior. Any HTML properly labeled on-whatever is intentionally not supported by CSS. (Full Properties Table)

The best way around this is to use jQuery, which sets up an interpreted engine in the background to execute what you were trying to do with the CSS anyway. See this page: Add Javascript Onclick To .css File.

Good luck.

Community
  • 1
  • 1
DragonLord
  • 6,395
  • 4
  • 36
  • 38
  • 2
    This answer is incorrect, and provides no explanation/justification for its claim that putting Javascript inside CSS is impossible. In fact, the other earlier answers *do* provide ways to put Javascript inside CSS (not portable, not supported on many browsers, but in some cases it *is* possible). – D.W. Oct 01 '14 at 21:25