How can I insert CSS styles inside <body> independent of specific elements?

Viewed 1361

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

6 Answers

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>

It is going to work in html5, even if it's regarded as invalid in html4.
I have an example from where I work now.

We are adding a slideshow for some books in a library catalogue and because this is done with a plugin the only possible way to style this is to include a <style> block with the html, as this plugin doesn't and shouldn't have access to <head> of the CMS it is designed for.

However, this solution is a last resort because of limitations of how the CMS is built and should be avoided.

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>

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/

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.

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>
Related