Home > Enterprise >  Is there a better way to apply CSS to details, but exclude summary?
Is there a better way to apply CSS to details, but exclude summary?

Time:12-24

I am using html5 summary/details on a page. (See screenshot below.) I want my details in a smaller font and indented when expanded. I've got the look I want using this using this CSS:

body {
  background-color: white;
  font-family: sans-serif;
  font-size: 16pt;
  line-height: 200%;
}

details {
  margin-left: 1.5em;
  font-size: 12pt;
  line-height: 120%;
}

details summary {
  cursor: pointer;
  font-size: 16pt;
  list-style: none;
  line-height: 200%;
  margin-left: -1.5em;
}

But, the way I've achieved it seems very inelegant. Because summary is a child element of details, I'm basically styling details and then overriding those changes in the CSS for summary. For example, increasing the left margin for details and then decreasing it by the same amount for summary.

I have tried using details:not(summary) and details:not(:first-child), hoping to exclude summary from the styling, but neither works as I would expect. The result is both details and summary being rendered in the smaller font size.

details:not(summary) {
  margin-left: 1.5em;
  font-size: 12pt;
  line-height: 120%;
}

Am I doing something wrong with the :not() selector? Is there any other way to style this that doesn't involve applying a style to details and then negating it for summary? (I'd rather not wrap things in a div or span if I can avoid it.)

About the screenshot...

homeassistant, node-red, mosquitto, and esphome are the summary elements. Only mosquitto has been opened to show details.

Screenshot

EDIT to include HTML...

The HTML is generated with Javascript because the information comes from an API call. Here's the bit for the summary/details:

    content  = `<details>\n`;
    content  = `<summary><img alt="${container.State}" src="icons/${stateIcon}"> ${container.Names[0].replace(/\//, '')}</summary>\n`;
    content  = `${imageTag}<br>\n${container.Status}<br>\n`;
    if (container.State == 'running') {
      content  = `<img alt="stop" src="icons/stop.svg"> <img alt="restart" src="icons/restart.svg"><br>\n`;
    }
    else {
      content  = `<img alt="start" src="icons/play.svg"><br>\n`;
    }
    content  = `</details>\n`;
  });
  document.getElementsByTagName('main')[0].innerHTML = content;

And here's the HTML from Firefox debug tools: enter image description here

CodePudding user response:

Make it easier on yourself and wrap the details text in a paragraph and then it's simple

* {   margin: 0;   padding: 0;   box-sizing: border-box; }  ::before, ::after {   box-sizing:inherit; }

body {
  background-color: white;
  font-family: sans-serif;
  font-size: 16pt;
}

details p{
  font-size: 12pt; 
  margin-left: 1.5em;
}

details summary {
  cursor: pointer;
  font-size: 16pt;
  list-style: none;
}
<details>
  <summary>Details</summary>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo non eaque ducimus.</p>
</details>

If you really don't want to add a paragraph, you have to calculate the offset of the summary based on text size using calc

* {   margin: 0;   padding: 0;   box-sizing: border-box; }  ::before, ::after {   box-sizing:inherit; }

body {
  background-color: white;
  font-family: sans-serif;
  font-size: 16pt;
}

details {
  font-size: 12pt;
  margin-left: 1.5em;
}

details summary {
  cursor: pointer;
  font-size: 16pt;
  list-style: none;
  margin-left: calc(12 / 16 * -1.5em);
}
<details>
  <summary>Details</summary>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo non eaque ducimus.
</details>

CodePudding user response:

I have accepted "wrapping the text in a P tag" from Paulie_D as the answer to my question. I am posting this for anyone curious about the implementation of it and how it affects the CSS and Javascript.

The CSS now looks like this...

body {
  background-color: white;
  font-family: sans-serif;
  font-size: 16pt;
  line-height: 200%;
}

details > p {
  margin-left: 2em;
  margin-top: 0;
  font-size: 12pt;
  line-height: 120%;
}

details > summary {
  cursor: pointer;
  list-style: none;
}

The Javascript that generates the HTML now looks like this...

    content  = `<details>`;
    content  = `<summary><img alt="${container.State}" src="icons/${stateIcon}"> ${container.Names[0].replace(/\//, '')}</summary>`;
    content  = `<p>`;
    content  = `${imageTag}<br>`
    content  = `${createDate}<br>`;
    content  = `${container.Status}<br>`;
    if (container.State == 'running') {
      content  = `<img alt="stop" src="icons/stop.svg"> <img alt="restart" src="icons/restart.svg"><br>`;
    }
    else {
      content  = `<img alt="start" src="icons/play.svg"><br>`;
    }
    content  = `</p>`;
    content  = `</details>`;
  });
  document.getElementsByTagName('main')[0].innerHTML = content;
  • Related