4

I am working on a WordPress theme and want to enable users to use full-width blocks in it. For this I am using the following HTML/CSS structure (reduced to the basic problem).

(note: although this is for a WordPress theme, the problem itself is not related to WordPress, but "only" a CSS problem, since I can even reproduce it with this very basic structure in a SO snippet)

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
}

.content {
  width: 100%;
  max-width: 400px;
  margin: 0 auto;
  overflow-y: visible;
  background: #eee;
}

.alignfull {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: #ccc;
}
<div class="content">
  <p>Some regular text. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante,
    dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui.</p>
  <p class="alignfull">
    Some more text - should be full width. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam
    lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. </p>
  <p>Some regular text again. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem
    ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. </p>
</div>

So there is a .content container with a max-width pixel value, horizontally centered by using margin: 0 auto;. In there, regular blocks (i.e. the first and last p here) will have the default width: auto, so they will be as wide as their parent .content.

To create a full-width container, the .alignfull class is applied (second p in my example). The left and right margins for this are defined as calc(50% - 50vw);, which (when the viewport is wider than the min-width of .content) should create a negative margin value that is exactly the distance between the content container and the edge of the viewport. That way that element should have the exact width of the viewport.

But that doesn't work: the .alignfull element ends up being wider than the viewport by a few pixels.

What I realized:

It has to do with the vertical scrollbar: If the whole content is less high than the viewport (i.e. if no vertical scrollbar is visible), the problem doesn't appear. So, when a scrollbar is present, 100% width of a full-width element is less than 100vw.

In the "official" Twentynineteen theme, this is solved in a completely different way which avoids the use of the vw unit and uses percentage values for the max-width of the content area. But I've seen tutorials that describe the method I have tried to use...

Is there any way to make it work properly using a px value for the content container's width/max-width, as I did?


Addition after first answer

I should add that I had already used another method with which I am also not happy. This defines a max-width for all direct children of the content container and changes that to 100% for .alignfull.

However, this brings some other problems along: Floated elements don't stay inside the content area, but are floated far left or right, and elements which by default have left/right margins (like blockquote) loose their margin settings, which are overwritten by the more specific .content>* selector's margin: 0 auto which is needed for centering. (see example below).

I know that the WordPress block editor puts floated images into a non-floated block (which would then get the max-width and be centered), but I'd like to be able to use the same CSS also for post formats for which the block editor is deactivated (using "Disable Gutenberg") and where therefore images are not necessarily wrapped in non-floated blocks, i.e. where floated images (which are not in any container elements) would end up far right/left.

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
}

.content>* {
  max-width: 400px;
  margin: 0 auto;
  background: #eee;
}

blockquote {
  margin: 30px 40px;
  background: #fc7;
  color: red;
}

.floated_img {
  float: right;
  width: 20%;
  height: auto;
}

.alignfull {
  max-width: none;
  background: #ccc;
}
<div class="content">
  <p>Some regular text. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante,dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui.</p>
  <img class="floated_img" src="http://lorempixel.com/output/food-h-c-117-198-7.jpg">
  <p>Some regular text. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante,dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui.</p>
  <p>Some regular text. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante,dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui.</p>
  <p>Some regular text. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante,dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui.</p>
  <p class="alignfull">
    Some more text - should be full width. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam
    lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. </p>
  <blockquote>This should be a blockquote</blockquote>
  <p>Some regular text again. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem
    ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. </p>
</div>
Johannes
  • 64,305
  • 18
  • 73
  • 130
  • I'm commenting so I can refer back to this question. With Gutenberg, I've relied on removing the centering container completely and using CSS to target elements like `p`, `ul`, etc. that are direct descendants of the main parent. I would love a better approach. Great question! – disinfor Nov 04 '19 at 17:54
  • `overflow-y: hidden;` to hide the scrollbar? There's a `rem` (root em) unit you could try instead of `vh` and there's also `vmin` and `vmax` that might help – Jay Nov 04 '19 at 18:06
  • @Jay That would not only hide the scrollbar, but cut off / hide any longer content... – Johannes Nov 04 '19 at 18:10
  • I guess there is no clean and generic solution but since we never really want the content to touch the edges, I would approximate it like this by simply reducing the values: https://jsfiddle.net/tuw8h46L/ – Temani Afif Nov 04 '19 at 20:16
  • @TemaniAfif Well - full-width *images* definitely *should* touch the edges... – Johannes Nov 04 '19 at 20:23

1 Answers1

2

You're right in saying that 100vw doesn't take into account scrollbars, and that's per spec. It's the viewport width, and whatever happens inside that viewport it doesn't care.

You could look at it the other way around: Make the default width 100%, and shunt the narrow items in from the sides.

You do, of course, run into the issue that the light grey background here doesn't extend into the margin between the items. I've hacked some compensation in here with padding, but you'll have to extend this logic to ensure padding collapses like margins do.

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
}

.content {
  width: 100%;
  margin: 0;
  overflow-y: visible;
}

.content > p {
  background-color: #eee;
  margin: 0;
  padding: 1em 0;
}

.content > p:not(.alignfull) {
  width: 400px;
  margin: 0 auto;
}

.content > p.alignfull {
  background: #ccc;
}
<div class="content">
  <p>Some regular text. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante,
    dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui.</p>
  <p class="alignfull">
    Some more text - should be full width. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam
    lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. </p>
  <p>Some regular text again. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem
    ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. </p>
</div>
Dan
  • 1,130
  • 2
  • 20
  • 38
  • Please note the addition to my question. I had tried similar methods before, but I would still like to find a way whrere the container elements defines the max-width. – Johannes Nov 04 '19 at 19:43