I'm applying CSS to the pre code
selector in order to make styled code blocks,like you'd see on GitHub or elsewhere. I'm using flexbox for the layout, and I have two "panel" divs side-by-side inside of a "box" div, one of which has a code block (Which is just code inside of <pre><code>
tags), and the "box" div is inside of a main "container" div.
The basic CSS I have is...
.*, *:before, *:after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
pre code {
display: inline-block;
overflow: auto;
white-space: pre;
padding: 1rem;
margin: 1rem;
}
.container {
display: flex;
flex-direction: column;
margin: 1rem;
gap: 1rem;
}
.box {
display: flex;
flex-direction: row;
gap: 1rem;
}
.panel {
display: flex;
flex-direction: column;
flex: 0.5;
padding: 1rem;
}
The two panels should be equal width, due to flex: 0.5
, however the right panel expands to fit the block, rather than the block shrinking to fit the panel.
If I set white-space: pre-wrap
on pre code
, I get the desired layout behavior, but then of course the code is word-wrapped, which I don't want.
And of course, if I use white-space: pre
and add a dedicated width to the pre code
, I get the desired behavior, where the code block has a horizontal scrollbar. I can't use a dedicated width, because I need the block to fit any panel it's inside of.
Setting width: 100%
on pre code
does nothing at all, for some reason.
Just to make sure I wasn't causing this error myself by doing something somewhere else, I put together this snippet to confirm my issue (I did add some background colors and margins to make the containers visible):
https://codepen.io/evprkr/pen/poKQXJr
CodePudding user response:
CSS issues causing your problems:
- There is an easy to miss initial
.
(dot) in your first line of CSS.*, *:before, *:after { }
. Therefore theborder-box
model is only applied to:before
and:after
pseudo elements. Oviously the same is true formargin
andpadding
. - None of the
.panel
ancestors have awidth
value set, this way flexbox cannot constrain child elements and will grow into infinity. flex: 0.5
(defaulting toflex: 0.5 1 0%
) apparently has no effect, as it does not widthflex-basis: 50%
. In both cases thepre code
will somehow not get triggered to overflow and therefore will not show a scrollable box. I cannot explain why, but it must be due to some W3C spec. However, the.panel width: 50%
you declared eventually resolves this issue.- Your combined use of
margin
s with the various elements andgap
produces seemingly unexpected overlapping of elements when resizing the browser/codepen. Even after removing the forementioned initial.
solution
- ad 1) Remove the
.
(dot) - ad 2) Assign
.container width: 100%
to give flexbox a constraint to work with. - ad 3) Remove
.panel flex: 0.5
and assign.panel width: calc(50% - 0.5rem)
. Thecalc(..)
is required, becausegap
adds to the total width of the.panel
s, potentially causing them to overlap on resize. As yourgap: 1rem
adds0.5rem
to each of the two columns, that value needs to be subtracted from thewidth
of each column. - ad 4) Like
gap
,margin
adds to the total width of an element which would require you to subtract left and/or right margins from element widths to prevent them from overlapping other elements. The easiest way to circumvent having to add extracalc(..)
in your CSS, movemargin
of an element to thepadding
of its direct parent element. This will not be true in all circumstances, but in this instance it works out just fine without changing the overall layout.
Bonus
For responsive behaviour:
- Allow
.box
to wrap its child elements - Set some required minimum
.panel width
to force.box
to wrap its child.panel
s. I chose300px
in this instance. - This requires the
.panel
elements to be allowed grow to the full50%
when not wrapping.
And hyphen
ate text for readability...
snippet
*, *:before, *:after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
pre code {
background: #d7d7db;
display: block;
overflow: auto;
white-space: pre;
padding: 1rem;
}
.container {
background: #0197f4;
display: flex;
flex-direction: column;
padding: 1rem;
width: 100%;
}
.box {
background: #ff7538;
display: flex;
flex-flow: row wrap;
gap: 1rem;
padding: 1rem;
}
.panel {
background: #fff;
display: flex;
flex-direction: column;
padding: 2rem;
/* Adjust for parent gap value */
width: calc(50% - 0.5rem);
/* Allow to grow and wrap when less than 300px */
flex: 1;
min-width: min(300px, 100%);
}
.text { hyphens: auto }
<div >
<div >
<div >
<div >Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi accumsan mattis ullamcorper. Nulla tincidunt aliquam feugiat. Sed imperdiet tellus ligula, vehicula condimentum neque venenatis ut. Aenean varius elementum nulla, vehicula laoreet erat aliquam at. Nullam venenatis ex id tincidunt fringilla. Vivamus nec tellus sit amet leo tristique luctus. Cras elementum at diam at viverra. Phasellus tristique elementum velit id tincidunt. Nullam ullamcorper fringilla nulla sed ultricies.</div>
</div>
<div >
<pre><code>function SomeFakeFunction(first_argument, second_argument) {
if (first_argument > second_argument) {
return "first argument is greater than second argument";
} else if (first argument < second_argument) {
return "first argument is less than second argument";
}
return "first argument and second argument are equal (or invalid but this is just filler code so i don't care to write anymore honestly)"
}</pre></code>
</div>
</div>
</div>