|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "The Gutenberg Layout Problem" |
| 4 | +permalink: "blog/the-gutenberg-layout-problem" |
| 5 | +categories: |
| 6 | + - WordPress |
| 7 | +comments_id: 11 |
| 8 | +--- |
| 9 | + |
| 10 | +The Gutenberg editor is amazing. It allows for flexibility that was previously unheard of without a dedicated page builder. And though everyone kept saying "_Gutenberg is not a page-builder_", I think there's no denying it. **It is a page-builder**. You can call it an immersive editing experience for all I care, but the truth is it's a page-builder. |
| 11 | + |
| 12 | +With all the good things it brought, there were (and still are) some difficulties, mostly regarding the way we can style things - both in the editor and the frontend. This post is about one of the many solutions that you can implement, depending on your layouts. |
| 13 | +If your theme doesn't have a sidebar and instead the content is the whole viewport-width, then things are pretty simple. In the [Gridd](https://wplemon.com/gridd) however **there is no standard layout**. Users build their own grid. A site may be just a logo on the top and then the content, or it can have 4 widget-areas on the sides. And therein lies the problem: |
| 14 | +How can we account for ALL cases? |
| 15 | + |
| 16 | +## What Gutenberg generates |
| 17 | + |
| 18 | +I created a dummy post with all the cases I could think of at the time, so this is what we'll try to accomplish: |
| 19 | + |
| 20 | +<img src="https://aristath.github.io/assets/article_images/screenshot_2019-10-29-test-post-localhost.png" alt="screenshot of a post written in the WordPress editor using a normal paragraph, a wide element, a full-width element, some dummy content and 2 buttons - one of them floating on the left and a 2nd one floating on the right."> |
| 21 | + |
| 22 | +First of all we have the Gutenberg-generated HTML: |
| 23 | + |
| 24 | +```html |
| 25 | +<div class="my-container"> |
| 26 | + <div class="entry-content container"> |
| 27 | + <p class="has-background has-very-light-gray-background-color">Normal content.</p> |
| 28 | + <div class="wp-block-group alignwide has-very-dark-gray-background-color has-background"> |
| 29 | + <div class="wp-block-group__inner-container"> |
| 30 | + <p class="has-text-color has-very-light-gray-color">Wide content.</p> |
| 31 | + </div> |
| 32 | + </div> |
| 33 | + <div class="wp-block-group alignfull has-vivid-red-background-color has-background"> |
| 34 | + <div class="wp-block-group__inner-container"> |
| 35 | + <p class="has-text-color has-very-light-gray-color">Full-width content.</p> |
| 36 | + </div> |
| 37 | + </div> |
| 38 | + <div class="wp-block-button alignleft"> |
| 39 | + <a class="wp-block-button__link">button floating left</a> |
| 40 | + </div> |
| 41 | + <p>Text next to the button.</p> |
| 42 | + <p>Some more content here.</p> |
| 43 | + <div class="wp-block-button alignright"> |
| 44 | + <a class="wp-block-button__link">button floating right</a> |
| 45 | + </div> |
| 46 | + <p>Some more text</p> |
| 47 | + <p>and yet some more to show the button float.</p> |
| 48 | + </div> |
| 49 | +</div> |
| 50 | +``` |
| 51 | + |
| 52 | +The wrapping `my-container` element there is just our theme's wrapper for the content. |
| 53 | + |
| 54 | +## Styling |
| 55 | + |
| 56 | +In the code above we can see a lot of classes, most of them color-related. I added them when editing the post to make it clear in the screenshot what each element is and what its dimensions are. But here are the important ones and what they should do: |
| 57 | + |
| 58 | +* `.alignwide` makes an element wider than the normal content. |
| 59 | +* `.alignfull` makes an element span the full width of its parent container. |
| 60 | +* `.alignleft` floats an element to the left - while still keeping it inside the constraints of the "regular" content's width |
| 61 | +* `.alignright` - similar to `.alignleft`, but obviously floating on the right side. |
| 62 | + |
| 63 | +What we _need_ to accomplish: |
| 64 | + |
| 65 | +* We want our normal content to have a maximum width of `50em`. |
| 66 | +* Elements that have the `.alignwide` class should be 25% wider than normal content. |
| 67 | +* Elements with the `alignfull` class should be 100% of their container. |
| 68 | +* We also want a padding on 1em on the left & right of our elements, otherwise on mobile they're going to stick to the edges of the window. |
| 69 | + |
| 70 | +Let's start by adding our defining some variables, and add the padding to our container: |
| 71 | + |
| 72 | +```css |
| 73 | +.my-container { |
| 74 | + --padding: 1em; |
| 75 | + --content-width: 50em; |
| 76 | + --wide-diff: 25%; |
| 77 | + --wide-width: calc(var(--content-width) * 1.25); |
| 78 | + |
| 79 | + padding: 0 var(--padding) 0 var(--padding); |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +### Normal elements |
| 84 | + |
| 85 | +Next up, we can start adding styles for elements that should have a normal width: |
| 86 | + |
| 87 | +```css |
| 88 | +.entry-content > :not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright) { |
| 89 | + max-width: var(--content-width); |
| 90 | + margin-left: auto; |
| 91 | + margin-right: auto; |
| 92 | +} |
| 93 | +``` |
| 94 | + |
| 95 | +The above is fairly simply: For all elements that are direct children of our main container, if they are not alignfull/alignwide/alignleft/alignright we're adding our content-width css-variable as the element's maximum width. |
| 96 | +Once we do that, we notice that the element is on the left of the screen, so we're adding the margin-left and margin-right lines and set them to auto. This way our element gets properly centered. |
| 97 | + |
| 98 | +### `.alignwide` elements |
| 99 | + |
| 100 | +Moving on to the "wide" elements: |
| 101 | + |
| 102 | +```css |
| 103 | +.entry-content .alignwide { |
| 104 | + width: calc(var(--content-width) + var(--wide-diff) + 2 * var(--padding)); |
| 105 | + max-width: 100%; |
| 106 | + margin-left: auto; |
| 107 | + margin-right: auto; |
| 108 | +} |
| 109 | +``` |
| 110 | +This here is a bit more complicated: To calculate the width of our element we're adding the `--wide-diff` var to our content-width, and then we also add the padding (doubled since it exists both on the left and right of our container). |
| 111 | + |
| 112 | +### `.alignfull` elements |
| 113 | + |
| 114 | +The "full" elements are not without their difficulties too: |
| 115 | + |
| 116 | +```css |
| 117 | +.entry-content .alignfull { |
| 118 | + transform: translateX(calc(0px - var(--padding))); |
| 119 | + width: calc(100% + 2 * var(--padding)); |
| 120 | + max-width: calc(100% + 2 * var(--padding)); |
| 121 | + margin-left: auto; |
| 122 | + margin-right: auto; |
| 123 | +} |
| 124 | +``` |
| 125 | +For these ones we have to move the element to the left by the amount of our defined padding, and then set its width to be equal to 100% of our available space, plus the padding doubled so there's no space on the left and right. |
| 126 | + |
| 127 | +### `.alignleft` & `.alignright` elements |
| 128 | + |
| 129 | +Now that we're done with the basics let's move on to the hard part: Getting the floats right. |
| 130 | + |
| 131 | +By default these are not restricted by the `50em` we want for our content since they use `float`. As a result they will literally float to the edges of the screen. Well, not quite the edge, `1em` from the edge 'cause that's the padding we have defined. So how do we get them to be within the limits of our invisible and theoretical "normal content" box? |
| 132 | + |
| 133 | +The best solution I could come up with so far is this: |
| 134 | + |
| 135 | +```css |
| 136 | +.entry-content .alignleft { |
| 137 | + float: left; |
| 138 | + margin-left: calc(50% - var(--content-width) / 2); |
| 139 | +} |
| 140 | + |
| 141 | +.entry-content .alignright { |
| 142 | + float: right; |
| 143 | + margin-right: calc(50% - var(--content-width) / 2) |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +The above snippet will add a left margin to elements that are floated to the left and a right margin to elements floated to the right, therefore displacing them visually and moving them to the place we need the to be. It's counter-intuitive and I absolutely hate it. It's an ugly hack that makes absolutely no sense. But it works (most of the time). |
| 148 | + |
| 149 | +In some cases you may need to also add something like this: |
| 150 | + |
| 151 | +## Got a better idea? |
| 152 | + |
| 153 | +How do you handle this? Do you have a better idea? If you do, please let me know. I've been banging my head against the wall for a long time trying to find an elegant solution. |
0 commit comments