Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add content-width option to global-styles & theme.json #25160

Closed
aristath opened this issue Sep 8, 2020 · 23 comments
Closed

Add content-width option to global-styles & theme.json #25160

aristath opened this issue Sep 8, 2020 · 23 comments
Labels
[Feature] Themes Questions or issues with incorporating or styling blocks in a theme. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json

Comments

@aristath
Copy link
Member

aristath commented Sep 8, 2020

Spawned from #20771

I started building a block-based theme from scratch today, and was surprised by how hard it still is to do some things.
The hardest part when creating a theme for use with the editor is figuring out how to handle the following:

  • Add max-width to blocks so they are limited to a pre-defined content-width
  • Handle alignwide
  • Handle alignfull

Writing the CSS for these things is an absolute nightmare, especially in FSE where the user can add a sidebar, 2 sidebars, have nested columns within groups that are nested in columns and so on.

Generating these styles automatically would be ideal, and if done properly would solve a lot of issues.

theme.json

In theme.json we could use 2 options:

  • contentWidth: (string) can use any CSS value (90%, 1000px, 60em etc)
  • alignWideWidth: (string|number) If string then any CSS value. If number then assume proportionate to the contentWidth (1.25 would be 1.25 times the contentWidth).

Global Styles

In global-styles we'd need a setting for the content-width.
Adding the align-wide-width option would be of secondary importance and not really necessary. Good to have, but not a requirement.


EDIT: After further experimentation I realized that what we need is not a site-width as this original post was stating, but a content-width.
Site-width would be useful when building a "boxed" layout, which is not what most people will want. Content-width on the other hand describes more accurately what this is about: Setting a max-width for the actual blocks.
The site-width can be accomplished with columns if needed (3 columns, with the middle one set to 900px and the other 2 left to auto-calc)

@kjellr
Copy link
Contributor

kjellr commented Sep 8, 2020

Adding the align-wide-width option would be of secondary importance and not really necessary. Good to have, but not a requirement.

This would be a nice first step towards letting Gutenberg handle wide/full alignments styles on the front end. Gutenberg already makes this work in the editor, but theme authors have to write (in some cases, a lot of) styles on the front-end to implement the alignments there too. They shouldn't need to do that in the future, especially when block-based themes become the standard.

@ZebulanStanphill ZebulanStanphill added the Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json label Sep 8, 2020
@aristath aristath added the [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. label Sep 9, 2020
@aristath aristath changed the title Add site-width option to global-styles & theme.json Add content-width option to global-styles & theme.json Sep 9, 2020
@aristath
Copy link
Member Author

aristath commented Sep 9, 2020

Regarding the generated CSS, as I meantioned before it's a nightmare to get t right - especially on layouts with sidebars.
Below is an example I found works in all cases, regardless of the layout used:

:root {
    font-size: 22px;
    --contentWidth: 900px;
    --wideWidth: calc(1.25 * var(--contentWidth));
}

.wp-block-post-content {
    --paddingHorizontal: 1em;
    padding: 0 var(--paddingHorizontal);
}

.wp-block-post-content > * {
    max-width: var(--contentWidth);
    margin-left: auto;
    margin-right: auto;
}

.wp-block-post-content .alignwide {
    width: calc(var(--wideWidth) + 2 * var(--paddingHorizontal));
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
}

.wp-block-post-content .alignfull {
    transform: translateX(calc(0px - var(--paddingHorizontal)));
    width: calc(100% + 2 * var(--paddingHorizontal));
    max-width: calc(100% + 2 * var(--paddingHorizontal));
    margin-left: auto;
    margin-right: auto;
}

.wp-block-post-content .alignleft {
    float: left;
    margin-left: calc(50% - var(--contentWidth) / 2);
}
  
.wp-block-post-content .alignright {
    float: right;
    margin-right: calc(50% - var(--contentWidth) / 2)
}       

It is something that I've been working on for a long time on various themes, and so far doesn't seem to have any issues.
The downside is that it's a complicated solution, but that's only because the nature of the problem is complex.
What the above code does:

  • Adds a left/right padding to the content. This helps for mobile views so the content doesn't go to the very edge of the screen which can be extremely annoying.
  • Adds a width to alignwide elements, taking the padding into account
  • Properly positions the alignfull elements
  • Works with any number of sidebars in the layout etc
  • Properly styles floated elements

In the above code I'm only doing this for .wp-block-content, but I'm sure we can abstract the logic and make it work everywhere.

@ZebulanStanphill
Copy link
Member

Why can't the .wp-block-post-content > :not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright) selector just be .wp-block-post-content > *? I don't like the heavy use of :not here; it feels really fragile to me, and it increases the specificity a lot.

@aristath
Copy link
Member Author

Good point, updated 👍

@scruffian
Copy link
Contributor

What do you think about adding box-sizing: border-box so that we don't have to do so many calculations for padding?

(See #25115)

@aristath
Copy link
Member Author

What do you think about adding box-sizing: border-box so that we don't have to do so many calculations for padding?

I don't see why not... Feel free to post code with the box-sizing mod so we can find a solution that will work for everyone and move forward with this 👍

Also adding a link to a codepen by @jasmussen: https://codepen.io/joen/pen/oEYVXB (see comment on an older issue)

@aristath
Copy link
Member Author

aristath commented Sep 11, 2020

Thank you @scruffian for your suggestion to use border-box.

The bare minimum I have to make alignments work properly regardless of the layout is now this:

:root {
    --contentWidth: 900px;
    --wideWidth: calc(1.5 * var(--contentWidth));
}

* {
    box-sizing: border-box;
}

.wp-site-blocks {
    --paddingHorizontal: 1em;
    padding: 0 var(--paddingHorizontal);
}

.wp-site-blocks > *:not(.wp-block-post-content),
.wp-site-blocks .wp-block-post-content > * {
    max-width: var(--contentWidth);
    margin-left: auto;
    margin-right: auto;
}

.wp-site-blocks .alignwide {
    width: var(--wideWidth);
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
}

.wp-site-blocks .alignfull {
    transform: translateX(calc(0px - var(--paddingHorizontal)));
    width: 100%;
    max-width: 100%;
    box-sizing: content-box;
}

.aligncenter {
    text-align: center;
}

.wp-site-blocks .alignleft {
    float: left;
    margin-right: 2em;
    max-width: 360px;
}

.wp-site-blocks .alignright {
    float: right;
    margin-left: 2em;
    max-width: 360px;
}       

A lot cleaner... and I think with a couple more tweaks we should be able to have a result that we can automatically add to FSE themes, taking the content-width setting into account.

@kjellr
Copy link
Contributor

kjellr commented Sep 11, 2020

The bare minimum I have to make alignments work properly regardless of the layout is now this:

These rules should probably cover nested children too, right?

@aristath
Copy link
Member Author

These rules should probably cover nested children too, right?

They do, yes. I added a test layout where I have a group, inside the group a columns block, then on one of the columns a group, and inside the group I added the content block. All styles are properly applied on the global layout and the content. 😄

@scruffian
Copy link
Contributor

Thanks for this. I'm still not convinced that we're taking the right approach with full alignments. The way we are implementing wide at the moment seems to make is almost redundant. In most cases content will fill most of its container, with a small padding/margin to give it space. The wide alignment then stretches the content to fill the entire parent, which means that full doesn't do anything different. To me it makes more sense for full to always fill the entire viewport. Some blocks would then need to remove the full alignment option if it didn't make sense in that context.

@aristath
Copy link
Member Author

aristath commented Sep 14, 2020

The way we are implementing wide at the moment seems to make is almost redundant. In most cases content will fill most of its container, with a small padding/margin to give it space.

Not quite... It depends on the layout and the content-width.
On a 2000px-wide screen with a 600px-wide content, wide could be 800px, making it significantly different to full. It depends on the theme you're using, how that theme implements wide/full, and in FSE themes it also depends on what kind of layouts the site-admin will create.

The wide alignment then stretches the content to fill the entire parent, which means that full doesn't do anything different.

Where are you seeing this exactly?

To me it makes more sense for full to always fill the entire viewport

That would only make sense in a layout without sidebars, it can't work like that when there is a sidebar otherwise the full elements would overlap the sidebar and would be off-center when compared to the rest of the content (which will be offset because of the sidebar width)

@jasmussen
Copy link
Contributor

I would agree with @scruffian. I'm not sure content-width has a place in a responsive world. I understand how it could support how we currently do full-wide, but it seems like that could be refactored entirely.

Specifically I've noticed as I'm increasingly using the site editor, that when I insert a block there, at the root of the document, I would expect it to not be constrained to a centered column, and that the ability for Post Content to constrain the content inside is a somewhat unique behavior which, while it should definitely be retained, should not be the default for blocks or template parts or anything else inserted into the site editor.

There's some great conversation about how wide and fullwide alignments can be refactored in #20650. I can't find it now, but some of the related conversation I had with @youknowriad about it involved treating wide alignment as a property of, for example, template parts. Imagine you had a button in the block toolbar of a template part that said "constrain child blocks to a center column" (or something better), and that would enable the fullwide button for child blocks.

To be clear I'm not sure that's the solution either — conversations about grid features in #16998 seem to suggest there are additional ways to align blocks.

But in any case, I wouldn't want us to optimize too heavily towards how wide and fullwide alignments are handled today, as it's honestly a bit of a hack.

@aristath
Copy link
Member Author

Perhaps we mean different things when we talk about content-width then... Could very well be the cause of all the confusion.
By "content-width" I mean the max-width of the content. Not the width of the site, but the maximum width the actual text content can take for practical readability purposes.

Take for example the Wikipedia site... Their main article content area doesn't have a max-width defined. As a result, it's impossible to read anything on a large(ish) screen (anything above 17 inches) because of the extremely big line-width (far beyond the industry-standard 80 characters/line). I have to resize & halve my browser width every time I need to read something there...
Similarly, users (or themes) should be able to define a maximum width for their content so that it's readable. On my sites I use something like max-width: 55em; for the content, which combined with a responsive/adaptive typography-size works well for all device sizes and ensures my content will be easy for everyone to read.

With that in mind, there has to be some sort of "maximum content width" or "maximum characters per line" setting. And if there is such as setting, then the text content doesn't necessarily cover the full width of its container, it depends on what that container is, the content-width defined and the device used to consume the content. And if the content doesn't cover the full-width of its container for readability purposes, then wide/full both have a purpose.

Gutenberg is evolving into a page design tool, and in that context I agree that restricting the content-width will not always make sense.
But when used as a platform to write text content that people will need to read, there has to be some sort of max-width defined in the content itself.

@youknowriad
Copy link
Contributor

Related to #20650

One thing to consider here is that a single content width option is not a solution here. We need a content width for wide alignments and one for regular aligned blocks. We also need a way to define what alignments are supported on each "group block" (or template part). For example if I want to build a site that is split on two columns and each column need to support full/wide and regular alignments with its own widths, how do I do that.

the missing piece before diving into this work is that we need a good API and the InnerBlocks level to define these alignments/widths and how to consume them at the block child level.

@aristath
Copy link
Member Author

the missing piece before diving into this work is that we need a good API and the InnerBlocks level to define these alignments/widths and how to consume them at the block child level.

Well... With the above CSS, all we have to do in order to have different width depending on the container is to add inline styles to these innerBlocks and change the css-vars using --contentWidth: 300px; --wideWidth:400px;
The global styles work as expected, and nested elements can define their own maximum widths without complications 😉

@youknowriad
Copy link
Contributor

Do you think custom alignments are something that we want to support?

@aristath
Copy link
Member Author

Do you think custom alignments are something that we want to support?

It depends on what you mean by "custom alignments"...
We currently support left, right, center, wide, full, normal.
Anything besides those would be an edge-case. I can see for example someone wanting a mix of left-floated with a wide width, so it would look like this:

				Normal
			|******************|
				Wide
		****|******************|****
				Full
************|******************|************
				wide/left
		****|******************|

but these things would be extreme edge-cases and block-styles would be more suitable to handle things like that on a per-block basis

@ZebulanStanphill
Copy link
Member

There's also the point to remember that most of these alignments aren't even "alignments" in the traditional sense of the word. Wide/full are widths, not true alignments. Left/right are really floats, and their exact behavior actually varies somewhat since some themes use negative margins to pull the block outside of the main column entirely. (Twenty Twenty does this.) Center is the only thing that could actually be considered a true alignment.

So the inconsistent implementation of these options makes things complicated. What exactly is supposed to be the difference between "no alignment" and "center alignment"? Should pulling stuff out of the main column like the left/right options on Twenty Twenty really be considered the same thing as a standard float without any negative margins?

It's also worth noting that even though 2 of the options are widths, 2 are float options, and 1 is an actual alignment, you would almost never use any of them at the same time. I can't see a reason to use wide/full with a float unless you just want to end up with the same result that the float options already do on a theme like Twenty Twenty.

😵

@scruffian
Copy link
Contributor

Where are you seeing this exactly?

Content in columns is a good example. Inside a column the difference between wide and full is hard to notice. You can see a similar thing in this example for the group block.

image

If you have a full block inside a group block you need both that block and its parent group block to be full for it to fill the screen. This seems to create problems as we move towards a place where everything is a block. If I want to have a full image inside a post block, I would also need the post block to be full. Does that make the problem clearer?

That would only make sense in a layout without sidebars, it can't work like that when there is a sidebar otherwise the full elements would overlap the sidebar and would be off-center when compared to the rest of the content (which will be offset because of the sidebar width)

In that case I think we might need to look to different ways to solve the problem. A block should be able to prevent its children from setting full alignments. This would be useful on column blocks for example.

@aristath
Copy link
Member Author

The examples posted in the screenshot above are totally dependent on the theme's styles.
The theme uses a standard, fixed width for the content. But that's not necessarily always true... It wouldn't happen if the theme was using percent values for the content-width, or even if it was using em values and changed the font-size in nested elements.
True, is some cases wide/full won't be different. But we can't assume that will always be the case, as it depends 100% on the theme used.

@nickfmc
Copy link

nickfmc commented Nov 22, 2020

@aristath Great job, this is the best alignment solution I have seen so far! kudos mate! Works great for theme developers as a starting point.

One thing, did you test the nesting in this way, if you have a group that is set to full width and then inside that you have another group you want to be contained by a standard wrapper. In my testing this just makes the nested group go full width? You could align it wide inside because we have a class for that but not standard width.

unless I approach it this way, which is not perfect because text inside an .alignfull is now contained, but if all blocks including text had align classes available without manually adding them this gets pretty close to being perfect for all scenarios I've come across.

sorry example in my sass implementation


.editor-content .alignfull {
  transform: translateX(calc(0px - #{$paddingHorizontal}));
  width: calc(100% + 2 * #{$paddingHorizontal});
  max-width: 100vw;
  margin-left: auto;
  margin-right: auto;
  > * {
    max-width: $wrapper-width-base;
    margin-left: auto;
    margin-right: auto;
    &.alignwide {
      width: $wrapper-width-wide;
      max-width: 100%;
      margin-left: auto;
      margin-right: auto;
    }
    &.alignfull {
      width: 100%;
      max-width: 100%;
      margin-left: auto;
      margin-right: auto;
    }
  }
}

@carolinan
Copy link
Contributor

Do we consider this solved with the addition of the layout setting? Should this be closed?

@youknowriad
Copy link
Contributor

Sounds like it to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Themes Questions or issues with incorporating or styling blocks in a theme. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json
Projects
None yet
Development

No branches or pull requests

8 participants