5

Traditionally, you can add CSS in three ways:

  1. External CSS via <link rel="stylesheet" href="foo.css">
  2. Internal CSS via <style> h1 { ... } in the <head> element
  3. Inline CSS via the style="..." attribute on specific elements

Inline CSS has the drawback that I can't use CSS classes, which is something I need to do. Is there a way to define internal CSS (e.g. a <style></style> fragment in the <body> element?

This would be much easier for me because I could create a self-contained HTML snippet with a method in my server code. This kind of method is necessary because I don't control the <head> section. It is owned by a commercial product. I can only insert content inside the <body>.

Example:

<div>
 <style>
  .myclass {...}
 </style>
 <div class="myclass">...</div>
</div>

Related: https://htmx.org/essays/locality-of-behaviour/

I have seen other websites (like https://amazon.com) where they appear to have several style tags inside the <body>.

There is a huge gap between theory and practice. Many sites use <style> in the body.

The editors decided against it. But maybe there will be a change in the future: https://github.com/whatwg/html/issues/1605

guettli
  • 25,042
  • 81
  • 346
  • 663
  • 4
    ` – Mihai T Jul 29 '21 at 06:53
  • 1
    OK - would [custom web components](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) be of use - they can contain their own css that does not propogate to the parent DOM and is available within the component immediately – Professor Abronsius Jul 29 '21 at 07:05
  • Check this: https://stackoverflow.com/questions/38941889/how-to-apply-imported-stylesheet-to-template-tag-content-for-a-custom-element – Chris P Sep 06 '21 at 22:31

5 Answers5

7

Under the premise, you don't care about invalid HTML in relation of <style> inside <body> (which is not that uncommon), you can assign unique identifier i.e.:

<style>
  .my-class-1 {
    color: gold;
  }
</style>
<div class="my-class-1">Fragment Content</div>

<style>
  .my-class-2 {
    color: tomato;
  }
</style>
<div class="my-class-2">Fragment Content</div>

<div class="my-fragment-1">
  <style>
    .my-fragment-1 .my-class {
      color: teal;
    }
  </style>
  <div class="my-class">Fragment Content</div>
</div>

<div class="my-fragment-2">
  <style>
    .my-fragment-2 .my-class {
      color: hotpink;
    }
  </style>
  <div class="my-class">Fragment Content</div>
</div>

<style id="my-style-1">
  #my-style-1 + div {
    color: orangered;
  }
</style>
<div>Fragment Content</div>

<style id="my-style-2">
  #my-style-2 + div {
    color: indigo;
  }
</style>
<div>Fragment Content</div>
tom
  • 9,550
  • 6
  • 30
  • 49
  • What can you do if there is a big difference between the specification and the daily practice? Change the daily practice, or adapt the spec? – guettli Sep 11 '21 at 09:13
  • To have no access to the `` section is somehow an unsual practice. But see this [discussion](https://stackoverflow.com/a/50154225/10944219). It seems that it is implemented in HTML5.2 [W3C](https://www.w3.org/TR/html52/document-metadata.html#the-style-element) _... should be used with care ..._ . At least be aware of [Flash of unstyled content](https://en.wikipedia.org/wiki/Flash_of_unstyled_content) what is usualy caused by styles placed in the `` and be loaded afterwards. That's why I prevent it. FOUC and FOIT is not very user friendly. – tom Sep 11 '21 at 11:35
1

the simpler answer to your question is "Yes" and I'll elaborate on this with several examples below. A <style> tag will work wherever you place it within either the <head> or the <body>.

A style tag placed in the <body> tag technically does violate HTML syntax rules, it's surprisingly common in practice, even among some larger corporations.

There are several different methods for including <body>-level <style> tags in your project.

1. Pure HTML <style> tags (the static method)

If you have all the styles you need already written up and there are no dynamic pieces needed, you can simply write those styles into a <style> tag statically and include those in the code, as seen in this example below:

<html>
  <head></head>
  <body>
    <div class="custom-widget">
      <h1>This is a title</h1>
      <p>This is some text.</p>
      <style>
        .custom-widget {
          display: block;
          padding: 20px;
          border: 5px double red;
        }
        .custom-widget h1 {
          text-transform: uppercase;
        }
        .custom-widget h1::first-letter {
          font-size: 150%;
        }
        .custom-widget p {
          font-style: italic;
        }
      </style>
    </div>
  </body>
</html>

2. Writing the styles into a <style> tag as text using JavaScript

If you need to load the styles into your <style> tag dynamically and you simply need plain text styles that you will not need to change much after creating them. You can create the <style> block and then inject the CSS styles as plain text as desired, as seen in this example below:

const counter = document.getElementById('counter');
  let count = +counter.dataset.count;
const customWidgetStyle = document.querySelector('.custom-widget style'),
      countdown = setInterval(() => {
        if (count--) {
          counter.innerText = `Importing CSS in ${count}…`;
        } else {
          clearInterval(countdown);
          counter.remove();
          customWidgetStyle.innerHTML = `
            .custom-widget {
              display: block;
              padding: 20px;
              border: 5px double red;
            }
            .custom-widget h1 {
              text-transform: uppercase;
            }
            .custom-widget h1::first-letter {
              font-size: 150%;
            }
            .custom-widget p {
              font-style: italic;
            }
          `;
        }
      }, 1000);
<html>
  <head></head>
  <body>
    <div class="custom-widget">
      <h1>This is a title</h1>
      <p>This is some text.</p>
      <style></style>
    </div>
    <span id="counter" data-count="3">Importing CSS in 3…</span>
  </body>
</html>

3. Creating cssRules styles into a <style> tag using the JavaScript CSSStyleSheet.insertRule() method

If you need even more flexibility with how you add your styles, you can use the CSSStyleSheet.insertRule() (MDN docs), which will dynamically allow you to add and manage the styles more granularly. This may be overkill for your specific need but there's a lot of power, flexibility, and control when working with the CSSOM.

Here is an example of this method, in which I use an addStylesheetRules function example defined on the MDN docs page for insertRule under the heading Examples, here:

const addStylesheetRules = (rules, stylesheet) => {
  if (stylesheet === undefined) {
    const style = document.createElement('style');
    stylesheet = style.sheet;
    document.head.appendChild(style);
  }
  for (let i = 0; i < rules.length; i++) {
    let j = 1,
        propStr = '';
        rule = rules[i];
    const selector = rule[0];
    if (Array.isArray(rule[1][0])) {
      rule = rule[1];
      j = 0;
    }
    for (let pl = rule.length; j < pl; j++) {
      const prop = rule[j];
      propStr += prop[0] + ': ' + prop[1] + (prop[2] ? ' !important' : '') + ';\n';
    }
    stylesheet.insertRule(selector + '{' + propStr + '}', stylesheet.cssRules.length);
  }
}

const customWidget = document.querySelector('.custom-widget'),
      customWidgetStyleTag = document.createElement('style');
customWidget.appendChild(customWidgetStyleTag);
const customWidgetStylesheet = customWidgetStyleTag.sheet;
addStylesheetRules([
  ['.custom-widget',
    ['display', 'block'],
    ['padding', '20px'],
    ['border', '5px double red']
  ],
  ['.custom-widget h1',
    ['text-transform', 'uppercase']
  ],
  ['.custom-widget h1::first-letter',
    ['font-size', '150%']
  ],
  ['.custom-widget p',
    ['font-style', 'italic']
  ]
], customWidgetStylesheet);
<html>
  <head></head>
  <body>
    <div class="custom-widget">
      <h1>This is a title</h1>
      <p>This is some text.</p>
    </div>
  </body>
</html>

Please let me know if there is any more context I can add to better answer your question.

Brandon McConnell
  • 5,776
  • 1
  • 20
  • 36
  • The "specificity" section seems like a complete non-sequitur. Why did you include it? Specificity has nothing to do with the question being asked. This answer would be improved by just removing that whole section. – TylerH Sep 07 '21 at 15:41
  • @TylerH I wanted to cover the advantages of specificity of including the CSS in components within the body rather than the head itself, but to make my answer more concise, I will remove it. Thank you. – Brandon McConnell Sep 07 '21 at 17:05
0

Couldn't you target the head element with Javascript and insert a style programmatically?

<script>
  var head = document.querySelector('head')[0];
  var css = 'div { background: red; }',
    
  var style = document.createElement('style');

  style.appendChild(document.createTextNode(css));

  head.appendChild(style) ;

</script>
Bogdan B
  • 846
  • 9
  • 23
0

As far as I can understand from the description you gave, you don't have the access to the <head>...</head> element, but you are free to edit the body. Also, you want to use CSS3 Classes, but with inline CSS, you can't.
I can't find a way in pure HTML/CSS, so I suggest you to use JQuery.

<script async src="https://cdn.statically.io/libs/jquery/3.6.0/jquery.min.js" />
<script>$('head').append('<style>/*Your styles here*/</style></script>');


Now, add classes to the html elements and edit the content between the <style /> tag.
Also, place this script at the end of <body> so that you can avoid the probable weird problems caused by placing this in between. XD
But remember, this will change the head after the user has loaded the page. So, theoretically, the users will first see an ugly html page without styles, then styles will be loaded and they'd see the page with styles.
For more explanation, check out the official documentation: https://api.jquery.com/append/

  • 1
    Please add further details to expand on your answer, such as working code or documentation citations. – Community Sep 06 '21 at 06:38
0

Your example should work. I work with WordPress using custom html where all the custom code goes into a <body> tag, and styling like so should work within each page (added more divs just to show an example that one style tag can hold classes for all divs within a div):

<div> 
   <style> 
      .className { ... }
      .classNameTwo{ ... } 
      .classNameThree{ ... }
   </style>
   <div class="className"></div>
   <div class="classNameTwo">
      <div class="classNameThree"></div>
   </div>
</div>
Amanda
  • 239
  • 1
  • 5