Reputation: 669
I have a blog article with code samples. For readability, the article's text is constrained to a certain maximum width. The code samples, however, may need to be wider than the maximum width of the text. What's the best way to accomplish this with HTML/CSS?
Here's a basic example illustrating the layout I'm trying to achieve as well as my problem.
body {
max-width: 650px;
border: 1px solid red;
margin: auto;
}
pre {
border: 1px solid green;
background-color: #eee;
}
<body>
<p>This is a sufficiently long paragraph. Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Quae hic rei publicae
vulnera inponebat, eadem ille sanabat. Ut id aliis narrare
gestiant? Cur iustitia laudatur? Nummus in Croesi divitiis
obscuratur, pars est tamen divitiarum.</p>
<p>This pre should be as wide as the first paragraph, even
when the viewport is narrower than 650px:</p>
<pre>small</pre>
<p>I want this pre to be wider than 650px no matter what the
viewport size is:</p>
<pre>this pre should be wider than the text above
<span>wxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz</span>
</pre>
</body>
Here are the key points:
pre
s must be constrained to a maximum width of 650px.pre
block should either be the width of its content or 650px, whichever is greater. No wrapping, no scrolling. Note that this means a pre
could be wider than its parent's width.Here's a screenshot of what I'd like to happen, note the second pre
that is wider than its parent:
I got as far as trying pre { display: inline-block; }
but this doesn't work in Safari. (The white space is significant to reproducing this Safari problem!)
I feel like a lot of people are having trouble understanding that I'm asking for a good way to make pre
blocks wider than their parent when the pre
content is wider than the parent.
Alternatively, I'll take any other sane way to have pre
blocks behave like min-width: 650px; max-width: fit-content;
, while the rest of the content on the page is max-width: 650px;
.
Upvotes: 4
Views: 646
Reputation: 669
I ended up more-or-less solving this. The basic approach is not to constrain the width of body
, but to constrain all children of body
instead, then relax pre
s. (Feel free to choose a container further down from the body, e.g. your div#main
or something.)
Note that I used display: table
on pre
because inline-block
seemed to prevent margin collapsing, which was important to me elsewhere in my real use of this, if not important for this simplified example.
I'm feeling pretty confident that Safari/WebKit has a bug (that Chrome has not!), so using JavaScript was unavoidable.
I think this behaves somewhat less nice on browsers that don't (yet) support max-width: fit-content
, but it does something acceptable there.
SO snippet below, but the CSS looks slightly prettier, IMHO, in Sass, which is how I originally wrote this solution: https://codepen.io/anon/pen/rrZVrg
function patchCodeSamplesForWebKit() {
for (const codeElem of document.querySelectorAll("pre")) {
if (codeElem.offsetWidth <= codeElem.parentNode.offsetWidth) {
// No problem with this one.
continue;
}
const treeWalker = document.createTreeWalker(codeElem,
NodeFilter.SHOW_TEXT);
let textNode;
while ((textNode = treeWalker.nextNode())) {
// console.log("Pre fix considering:", textNode);
const i = textNode.textContent.indexOf("\n");
if (i >= 0) {
// console.log("Splitting a text node for pre fix.");
textNode.splitText(i + 1);
}
}
}
// console.log("Completed pre fixes for safari.");
}
if (/\bAppleWebKit\b/.test(navigator.userAgent)
&& !/\bChrom(e|ium)\b/.test(navigator.userAgent))
{
if (document.readyState !== "loading") {
patchCodeSamplesForWebKit();
} else {
document.addEventListener("DOMContentLoaded",
patchCodeSamplesForWebKit);
}
console.log("Configured pre fix for WebKit/Safari.");
}
* {
box-sizing: border-box;
}
body {
margin: auto;
}
@media (min-width: 650px) {
body {
min-width: 650px;
max-width: 650px;
max-width: fit-content;
}
}
body > * {
max-width: 650px;
}
body > pre {
display: table;
max-width: none;
min-width: 100%;
}
@media (min-width: 650px) {
body > pre {
min-width: 650px;
}
}
body {
border: 1px solid red;
}
pre {
border: 1px solid green;
background-color: #eee;
}
<body>
<p>This is a sufficiently long paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae hic rei publicae vulnera inponebat, eadem ille sanabat. Ut id aliis narrare gestiant? Cur iustitia laudatur? Nummus in Croesi divitiis obscuratur, pars
est tamen divitiarum.</p>
<p>This pre should be as wide as the first paragraph, even when the viewport is narrower than 650px:</p>
<pre>small</pre>
<p>I want this pre to be wider than 650px no matter what the viewport size is:</p>
<pre>this pre should be wider than the text above
<span>wxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz</span>
</pre>
</body>
Upvotes: 1