WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.32k stars 4.12k forks source link

Allow responsive styles via theme.json #27107

Open jffng opened 3 years ago

jffng commented 3 years ago

Hello!

In the theme.json, it would be useful to specify different preset values depending on the viewport size.

The specific use case that comes to mind is font sizes. Just throwing this out there, but something like:

"global": {
    "settings": {
        "typography": {
            "fontSizes": [ 
                {
                    "slug": "regular",
                    "name": "Regular",
                    "mediaQuery": "screen and max-width( 782px )",
                    "size": "16px"
                },
                {
                    "slug": "regular",
                    "name": "Regular",
                    "size": "20px"
                }
            ]
...

As it stands, theme authors would have to specify one value in the theme.json and override it in CSS via a media query.

cc @MaggieCabrera @kjellr @nosolosw

aristath commented 3 years ago

My 2c is that we should not strive for pixel-perfect themes but instead we should move towards a pixel-agnostic way of thinking. Using breakpoints is one way of doing things, but it's not the only way. Breakpoints were invented when we had 2-3 basic viewports but nowadays we have anything from a 2-inch smartwatch to a 60-inch smart-TV and our sites need to play well everywhere.

Responsive typography can be achieved without breakpoints and one way to do that would be something like this:

{
    "global": {
        "settings": {
            "custom": {
                "typo": {
                    "rootSize": 16,
                    "adaptiveRatio": 0.8,
                    "scale": 1.333,
                }
            },
            "typography": {
                "fontSizes": [
                    {
                        "name": "small",
                        "slug": "small",
                        "size": "calc(var(--wp--preset--font-size--normal) / var(--wp--custom--typo--scale))"
                    },
                    {
                        "name": "Normal",
                        "slug": "normal",
                        "size": "calc(var(--wp--custom--typo--root-size) * 1px + var(--wp--custom--typo--adaptive-ratio) * 1vw)"
                    },
                    {
                        "name": "Medium",
                        "slug": "medium",
                        "size": "calc(var(--wp--preset--font-size--normal) * var(--wp--custom--typo--scale))"
                    },
                    {
                        "name": "large",
                        "slug": "large",
                        "size": "calc(var(--wp--preset--font-size--medium) * var(--wp--custom--typo--scale))"
                    },
                    {
                        "name": "Huge",
                        "slug": "huge",
                        "size": "calc(var(--wp--preset--font-size--large) * var(--wp--custom--typo--scale))"
                    }
                ]
            }
        }
    }
}

The above example has responsive-typography AND a consistent typography scale, all in one. It can even be tweaked to include clamp() in the CSS values if so desired.

I understand that most developers & designers have been working with breakpoints for a decade and it's hard to start thinking in a pixel-agnostic way, but it's where we should be going. I wouldn't want us to start advocating for the use of breakpoints when there are better ways out there to handle things...

MaggieCabrera commented 3 years ago

Actually, I didn't know we could do this, and I totally agree with you on breakpoints (at least in this particular case). clamp() is awesome and if the theme doesn't need to support IE or other old browsers (it doesn't work in some versions of iOS) it's definitely the way to go for this. Thanks for your comment @aristath

jffng commented 3 years ago

That's a good point @aristath!

However I do think it's idealistic, because there are use cases where a) you might want to change a variable other than size or b) having a responsive type scale would not work for the design.

Take Seedlet's primary navigation for example:

Desktop Mobile
Screen Shot 2020-11-30 at 3 27 59 PM Screen Shot 2020-11-30 at 3 27 38 PM

The type size becomes significantly larger on mobile, in addition to the font-family itself changing.

j-mccarthy commented 3 years ago

@aristath Your approach looks great. But not only is what @jffng an important point. @media queries may also be useful and required for certain base elements and not just the min/max-width features.

It's clear that breakpoints are not required for an adaptive typography scale, which we certainly need to be able to set as theme designers/developers. Yet, I personally still see a need to make adjustments to our base styles, based on the current viewing environment or, user choice for example https://www.w3.org/TR/mediaqueries-5/#mf-user-preferences. (Maybe not the best example for font-size, but see it as on the same trail.)

I only just got to the party. I'm super late. But am looking at this situation directly at the moment when writing my first block themes and attempting to write as little CSS in the theme, especially overriding block editor styles!

Luehrsen commented 2 years ago

At least for now not having breakpoint support would be a hard blocker against using theme.json and FSE. This is especially true for reasons mentioned above, where certain user interface elements should behave differently or not be visible at all on certain screens.

Media Queries are not going anywhere for the time being and considering all major css frameworks are building heavily on them makes me think that this is more wishful thinking than designing and building for what is already needed.

iandunn commented 2 years ago

I don't think it needs to be all-or-nothing. I've been trying to use techniques like clamp() first, and that often works. When it doesn't work, then I fall back to using media queries. There's nothing stopping you from manually adding breakpoint-specific variables to theme.json, or extra CSS on top of what Gutenberg generates.

skyshab commented 2 years ago

Just noting that the fluid typography approach mentioned above as a solution, does not in fact work with the Block Editor preview modes, as it is based on the width of the viewport. It also does not take the editor UI sidebars into consideration.

SamuelMiller commented 2 years ago

Allowing media query in theme.json would also make it easier to integrate Bootstrap 5 values into theme.json.

For example, bootstrap-reboot.css (Bootstrap Reboot v5.0.2 (https://getbootstrap.com/docs/5.1/content/reboot/#css-variable)) defines h1 property as this: h1 { font-size: calc(1.375rem + 1.5vw); } @media (min-width: 1200px) { h1 { font-size: 2.5rem; } }

For now, I'll use CSS Max, Min and Camp to approximate, but browsers prior to 2020 don't all support these newer CSS features.

By the way, there is a new excellent free Bootstrap plugin for WordPress called "All Bootstrap Blocks Plugin" by AREOI (https://areoi.io/all-bootstrap-blocks/). Which does an excellent job of integrating Bootstrap with WordPress. (I am not affiliated with the developer.)

skorasaurus commented 2 years ago

@jffng regarding fluid typography, that is actively being worked on at https://github.com/WordPress/gutenberg/pull/39529

jdm-web commented 1 year ago

Hi everyone.

I'd like to expand on this with another bit of context. Let's take the spacing / spacingScale setting for example. With these particular starting values :

      "spacingScale": {
        "operator": "*",
        "increment": 2,
        "steps": 6,
        "mediumStep": 2,
        "unit": "rem"
      },

This will generate 6 sizes like so :

    --wp--preset--spacing--30: 0.5rem;
    --wp--preset--spacing--40: 1rem;
    --wp--preset--spacing--50: 2rem;
    --wp--preset--spacing--60: 4rem;
    --wp--preset--spacing--70: 8rem;
    --wp--preset--spacing--80: 16rem;

Now imagine you apply the preset spacing 80 to an element using the margin slider, it will give you the following result :

<p style="margin-top:var(--wp--preset--spacing--80);margin-right:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80);margin-left:var(--wp--preset--spacing--80);padding-top:0;padding-right:0;padding-bottom:0;padding-left:0">Test content</p>

My original intention would be to wonder if I could decrease the spacingScale increment value on smaller screens, so that I can keep my variable names, but have lower generated sizes based on a media query. It is a bit similar than @jffng's original problematic.

Is there a way to generate dynamic values in this case? How would you address this rather common use case of reducing margins responsively so it stays relevant and doesn't look too gigantic on mobile?

Thank you.

justingolden21 commented 1 year ago

While for some people fluid type works well, nearly anyone who has a high profile website designed by an agency knows that they will often provide two mockups: mobile and desktop. Even if there are more screen sizes, hundreds of thousands of people design to fixed with containers in order to avoid having to design for every screen size and allowing them the freedom to focus on just a handful of finite designs. I dare say most people who design websites would design for specific breakpoints, and would have a specific font size for mobile and a specific font size for desktop, and often one to three more sizes. The face that this functionality is not natively available in WP forces all of those people to avoid theme.json entirely and go against the grain of WP, which is of course, not ideal.

I'm really surprised there hasn't been more conversation on this topic, as I see many people elsewhere demanding this feature as well. Rather silly that to have, for example, a heading of font size 2rem and 3rem on desktop, one is completely unable to use the gutenberg block and must make a custom component called a heading, register the block, and then invoke the block, and that this is true for literally all type across the entire website. Let's say you get a design that specifies h3 are 2rem on mobile and past 1024px are 3rem. This is literally impossible to implement without making a custom component for every single heading, or making a heading component with a huge drop down, not to mention paragraphs, subheadings, links, etc. It's just absurd. Everyone is forced into this fluid design or completely unable to use the theme.json whatsoever for any type.

PH4NTOMiki commented 1 year ago

It would be awesome if this ends up in production soon

QuietNoise commented 1 year ago

Breakpoints are current industry standard for responsive website, which very often does block element restacking on different screens (i.e. from 3 columns to 2) and fluid clamping with not work for many such scenarios. With the way theme.json works currently (throbbing global styles into html markup with !important tag) it is really hard and sometimes impossible to make it work with responsive approach.

theking2 commented 1 year ago

media hover:none

These styles will turn iinks in to hoverable objects but not on hover less devices (touch screens):

/* default hover effect */

@media (hover: hover) {
  a {
    color: inherit; /* use color of surrounding element */
    text-decoration: none;
  }
  /* when hover is supported */
  a:hover {
    color: blue; /* use default color of links, blue */
    text-decoration: underline;
  }
}

Support should be included not only for sizes but also for featrure media queries.

Lovor01 commented 11 months ago

Let me share my opinion on fluid vs breakpoints, given I do produce fluid themes. As @justingolden21 said, you often receive two (or more) designs built for particular screen. I am currently working with five, at 2560, 1920, 922, 921 and 357. I convert those designs to fluid design, typography is fluid (but fluid in sizes from 2560-922 and 921-357, two different formulas with breakpoint) and resizing elements is fluid, again often with breapoint at 921, where things start to rearrange to fit smaller screens. This is in-line with what @aristath wrote.

While I admit that fluid design is good idea, since it provides better UI across various devices, it still needs breakpoints.

There is much time I spend writing css instead of theme.json because some other elements change properties when above/below certain dimensions. For example:

So my conclusion is that breakpoints are still needed and will be needed, because mobile devices provide different challenges compared to desktop (because of small screen everything must be comparatively bigger to be readable and due to narrow space things must be re-shaped and rearranged).

So I vote for introduction of media queries into theme.json, but authors should be warned to use them sparingly and try to achieve fluid design instead.

Regarding fonts proposition, @aristath 's proposition has one missing point: font sizes in theme.json definition should be connected with screen widths, it is not developer-friendly to fix fluid typography to certain screen widths like it is now.

To help with managing fluid designs more easily, I even created this small library a while ago: https://github.com/Lovor01/interpolateCSS. However, I do not use it on every project, since it activates on page load event and therefore it can create some "jump" in design appearance (unless you have loader). This is necessary because library enables also attaching properties to other properties which are known only after load event. However I could rewrite it to split the loading in two parts, one in DomContentLoaded event for things dependent on window size and other in load for things dependent on screen elements.