themeum / kirki

Extending the customizer
https://kirki.org
MIT License
1.26k stars 327 forks source link

We need to reconsider how CSS variables work with Kirki #2019

Open rahulv3a opened 5 years ago

rahulv3a commented 5 years ago

I have been experimenting with CSS variables lately.

I went through #1561. In my opinion css_vars is more complex than it needs to be. Plus, it doesn't take into consideration that it is not necessary that variables are defined at root level. Plus, they also need to work with media queries.

We should use output instead and treat CSS variables as regular CSS properties. output in its current form already allows to use them to their full potential.

It is not necessary that CSS variables are defined at the root level.

They can be defined and manipulated CSS class level as well.

:root {
    --text-color: #333333;
    --background-color: #ffffff;
}

.dark-ui {
    --text-color: #ffffff;
    --background-color: #333333;
}

The folowing Kirki fields output the CSS code above:

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'multicolor',
    'settings'  => 'colors',
    'label'     => esc_attr__( 'Colors', 'textdomain' ),
    'section'   => 'section_1',
    'default'   => [
        'text'       => '#333',
        'background' => '#fff',
    ],
    'choices'   => [
        'text'       => esc_attr__( 'Text', 'aura-prime' ),
        'background' => esc_attr__( 'Background', 'aura-prime' ),
    ],
    'transport' => 'auto',
    'output'    => [
        [
            'choice'   => 'text',
            'element'  => ':root',
            'property' => '--text-color',
        ],
        [
            'choice'   => 'background',
            'element'  => ':root',
            'property' => '--background-color',
        ],
    ],
) );

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'multicolor',
    'settings'  => 'dark_ui_colors',
    'label'     => esc_attr__( 'Dark UI Colors', 'textdomain' ),
    'section'   => 'section_1',
    'default'   => [
        'text'       => '#fff',
        'background' => '#333',
    ],
    'choices'   => [
        'text'       => esc_attr__( 'Text', 'aura-prime' ),
        'background' => esc_attr__( 'Background', 'aura-prime' ),
    ],
    'transport' => 'auto',
    'output'    => [
        [
            'choice'   => 'text',
            'element'  => '.dark-ui',
            'property' => '--text-color',
        ],
        [
            'choice'   => 'background',
            'element'  => '.dark-ui',
            'property' => '--background-color',
        ],
    ],
) );

CSS variables can be used with Media Queries.

:root {
    --space: 20px;
}

@media (max-width: 1024px) {
    :root {
        --space: 40px;
    }
}

@media (max-width: 1200px) {
    :root {
        --space: 60px;
    }
}

The folowing Kirki fields output the CSS code above:

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'dimension',
    'settings'  => 'space',
    'label'     => esc_attr__( 'Space', 'textdomain' ),
    'section'   => 'section_1',
    'default'   => '20px',
    'transport' => 'auto',
    'output'    => [
        [
            'element'  => ':root',
            'property' => '--space',
        ],
    ],
) );

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'dimension',
    'settings'  => 'space_tablet',
    'label'     => esc_attr__( 'Space', 'textdomain' ),
    'section'   => 'section_1',
    'default'   => '40px',
    'transport' => 'auto',
    'output'    => [
        [
            'media_query' => '@media (max-width: 1024px)',
            'element'     => ':root',
            'property'    => '--space',
        ],
    ],
) );

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'dimension',
    'settings'  => 'space_desktop',
    'label'     => esc_attr__( 'Space', 'textdomain' ),
    'section'   => 'section_1',
    'default'   => '60px',
    'transport' => 'auto',
    'output'    => [
        [
            'media_query' => '@media (max-width: 1200px)',
            'element'     => ':root',
            'property'    => '--space',
        ],
    ],
) );

Typography field output already supports CSS variables partially

Everythying works except font-weight and font-style which are controlled by variant.

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'typography',
    'settings'  => 'typography',
    'label'     => esc_attr__( 'Typography', 'textdomain' ),
    'section'   => 'section_1',
    'default'     => array(
        'font-family'    => 'Roboto',
        'variant'        => 'regular',
        'font-size'      => '14px',
        'line-height'    => '1.5',
        'letter-spacing' => '0',
        'color'          => '#333',
        'text-transform' => 'none',
        'text-align'     => 'left',
    ),
    'choices'   => [
        'variant' => [
            'regular',
            'italic',
            '700',
            '700italic',
        ],
    ],
    'transport' => 'auto',
    'output'    => [
        [
            'choice'   => 'font-family',
            'element'  => ':root',
            'property' => '--body-font-family',
        ],
        [
            'choice'   => 'font-weight',
            'element'  => ':root',
            'property' => '--body-font-weight',
        ],
        [
            'choice'   => 'font-style',
            'element'  => ':root',
            'property' => '--body-font-style',
        ],
        [
            'choice'   => 'font-size',
            'element'  => ':root',
            'property' => '--body-font-size',
        ],
        [
            'choice'   => 'line-height',
            'element'  => ':root',
            'property' => '--body-line-height',
        ],
        [
            'choice'   => 'letter-spacing',
            'element'  => ':root',
            'property' => '--body-letter-spacing',
        ],
        [
            'choice'   => 'color',
            'element'  => ':root',
            'property' => '--body-color',
        ],
        [
            'choice'   => 'text-transform',
            'element'  => ':root',
            'property' => '--body-text-transform',
        ],
        [
            'choice'   => 'text-align',
            'element'  => ':root',
            'property' => '--body-text-align',
        ],
    ],
) );

The above Kirki fields output the following CSS code:

:root {
    --body-font-family: Roboto, Helvetica, Arial, sans-serif;
    --body-font-size: 14px;
    --body-line-height: 1.5;
    --body-color: #333333;
    --body-text-transform: none;
    --body-text-align: left;
}

All we need to ability to output font-weight and font-style with choice in the typography field and Kirki will be 100% compatible with CSS variables. css_vars can be safely deprecated.

rahulv3a commented 5 years ago

@aristath what are your thoughts about this?

rahulv3a commented 5 years ago

@aristath You have been pushing fixes for CSS-Vars. Just wondering if you have considered using output for the same?

aristath commented 5 years ago

I agree that the output argument is a lot more versatile, and it would make sense to use it. Currently I'm keeping it around 'cause it's a lot easier to write... For example instead of this:

'output' => [
    [
        'element'     => ':root',
        'property'    => '--space',
    ],
],

one can write this:

'css_vars' => '--space'

Adding a separate argument for css-vars was a matter of convenience and urgency, not one of structure. In the project I was (and still am) working on 99% of the time I need simple things like a font-size, a background-color etc. In fact I've built a theme using nothing but css-vars and it made the whole process a lot easier.

You're right, it would make sense to use the output argument. The plan is to internally map the css-vars to the output argument and remove the separate implementation that currently exists. For now however it doesn't hurt anyone or anything, and using a simpler syntax for the css-vars makes life a lot easier.

An internal reorganization of the code to map css-vars to output will be done. So it will basically just become a proxy for them in case we only need simple things. BUT it can't be removed. For better or worse I added the css-var argument and some people are already using it, so removing it now would be a bad idea.

That's why I'm leaving this ticket open. It serves as reminder of the pending refactor - but it's not on the top of the long list with todo items for the plugin. It will be done. :+1:

rahulv3a commented 5 years ago

I'm not against css_vars. I'm sorry if it seemed that way. I was suggesting that output should fully support it.

Currently there is no way to assign CSS variables for variants in the typography field. It would be great if something like the following would be possible:

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'typography',
    'settings'  => 'typography',
    'label'     => esc_attr__( 'Typography', 'textdomain' ),
    'section'   => 'section_1',
    'default'     => array(
        'font-family'    => 'Roboto',
        'variant'        => 'regular',
    ),
    'transport' => 'auto',
    'output'    => [
        [
            'choice'   => 'font-family',
            'element'  => ':root',
            'property' => '--body-font-family',
        ],
        [
            'choice'   => 'font-weight',
            'element'  => ':root',
            'property' => '--body-font-weight',
        ],
        [
            'choice'   => 'font-style',
            'element'  => ':root',
            'property' => '--body-font-style',
        ],
    ],
) );
ouun commented 5 years ago

@rahulvermadev you said that something like the following is working for your multicolor fields:

'output'    => [
                [
                    'choice'   => 'primary',
                    'element'  => ':root',
                    'property' => '--color-primary',
                ],
                [
                    'choice'   => 'secondary',
                    'element'  => ':root',
                    'property' => '--color-secondary',
                ],
                [
                    'choice'   => 'body',
                    'element'  => ':root',
                    'property' => '--color-body',
                ],
            ],

The above alows me to "preview" customizer changes via Postmessage but does not generate the expected CSS on frontend. On the other sie if I am using CSS Vars module like this:

'css_vars'  => [
                array( '--color-primary', '$', 'primary' ),
                array( '--color-secondary', '$', 'secondary' ),
                array( '--color-body', '$', 'body' ),
            ],

it behaves the other way around: Postmessage is not loading changes but it loads the correct CSS outside Customizer.

Now to have Customizer Postmessage loading the live CSS AND on the same time resulting in the CSS output outside Customizer I end up with that:

'css_vars'  => [
                array( '--color-primary', '$', 'primary' ),
                array( '--color-secondary', '$', 'secondary' ),
                array( '--color-body', '$', 'body' ),
            ],
            'output'    => [
                [
                    'choice'   => 'primary',
                    'element'  => ':root',
                    'property' => '--color-primary',
                ],
                [
                    'choice'   => 'secondary',
                    'element'  => ':root',
                    'property' => '--color-secondary',
                ],
                [
                    'choice'   => 'body',
                    'element'  => ':root',
                    'property' => '--color-body',
                ],
            ],

Not sure that is the expected behavior. I'm currently working with the development branch, could be related to that.

rahulv3a commented 5 years ago

@ouun The output method works in my themes. Have you correctly set choices and defaults?

If would be helpful if you could share the code of the whole field.

aristath commented 5 years ago

Closing this one. In v4.0 there is no longer a separate implementation for css-vars. They are instead just an alias with simplified syntax for the output argument, we'll keep the existing syntax around for backwards-compatibility purposes and nothing more.

ouun commented 5 years ago

Thanks @rahulvermadev & @aristath for your individual feedback. I am looking forward to the soultion for 4.0 and test it here again. Thanks anyways!

rahulv3a commented 5 years ago

@aristath are output and css_vars going to use same syntax in v4?

aristath commented 5 years ago

@aristath are output and css_vars going to use same syntax in v4?

Same syntax they have now. For backwards-compatibility everything will keep working the way it did. However, css_vars as an argument will not be documented anywhere is will only be used as a fallback in case themes use it. The recommended syntax for css-vars in v4.0+ will be using the output arg:

'output' => [
    [
        'element'  => ':root', // or whatever other element.
        'property' => '--my-var',
    ],
],

Using 'css_vars' => '--my-var', will internally convert to the above output syntax, so it's just a proxy. For details, this is the commit that handled the conversion from css-vars to output: https://github.com/kirki-framework/compatibility/commit/3398c179b099a493456ee6ed19c2e0d1bf23bef1 It will be in the kirki-framework/compatibility package which will be included in the plugin version and will handle all previous API requests and backwards-compatibility.

rahulv3a commented 4 years ago

@aristath Is there any way to assign values of font-weight and font-style to CSS variables with the typography control?

I need to have the following CSS:

:root {
    --body-font-family: 'Roboto',
    --body-font-family: 400',
    --body-font-style: normal,
}

I have the following code for the field:

Kirki::add_field( 'theme_config_id', array(
    'type'      => 'typography',
    'settings'  => 'typography',
    'label'     => esc_attr__( 'Typography', 'textdomain' ),
    'section'   => 'section_1',
    'default'     => array(
        'font-family'    => 'Roboto',
        'variant'        => 'regular',
    ),
    'transport' => 'auto',
    'output'    => [
        [
            'choice'   => 'font-family',
            'element'  => ':root',
            'property' => '--body-font-family',
        ],
        [
            'choice'   => 'font-weight',
            'element'  => ':root',
            'property' => '--body-font-weight',
        ],
        [
            'choice'   => 'font-style',
            'element'  => ':root',
            'property' => '--body-font-style',
        ],
    ],
) );
JiveDig commented 3 years ago

@rahulv3a did you figure this out for v3 which we're still on? I'm hitting the exact issue. I'm considering just adding it myself via 'kirki_my-option-name_styles' filter.

jessicadesjardins commented 3 years ago

Is there a resolution to this issue since it is marked as closed? It's essential to be able to output font-weight and font-style properties. Anybody have a workaround?

JiveDig commented 3 years ago

I ended up writing more code than I wanted to to add the variants manually via the filter above.

jessicadesjardins commented 3 years ago

I ended up writing more code than I wanted to to add the variants manually via the filter above.

Can you clarify which filter you're referring to? Do you mean kirki_{$config_id}_styles?

JiveDig commented 3 years ago

That’s the one :) mentioned in my above comment https://github.com/kirki-framework/kirki/issues/2019#issuecomment-724246273

jessicadesjardins commented 3 years ago

That’s the one :) mentioned in my above comment #2019 (comment)

Okay thanks! I wasn't sure if you meant the config ID or a setting's name. Is your code available to take a look at? Months later I'm literally still wishing I could figure this out... haha.

JiveDig commented 3 years ago

It's def tricky and I don't love our solution though it's working. Email me mike at bizbudding dot com and I can show you what we have.

rahulv3a commented 2 years ago

Here's how I add font-weight and font-style to the CSS generated by Kirki.

The only downside is 'transport' => 'auto' doesn't work with this solution.

Field code

Kirki::add_field( 'config_id', [
    'type'     => 'typography',
    'settings' => 'my_typography_field',
    'label'    => 'Body typography',
    'section'  => 'section_1',
    'default'  => [
        'font-family' => 'Roboto',
        'variant'     => 'regular',
    ],
    'output'   => [
        [
            'choice'   => 'font-family',
            'element'  => ':root',
            'property' => '--body-font-family',
        ],
    ],
] );

Code that updates Kirki's CSS

add_action( 'kirki_config_id_styles', 'theme_prefix_add_typography_css' );

function theme_prefix_add_font_variant_css( $css ) {
    // Get variant.
    $variant = get_theme_mod( 'my_typography_field' )['variant'];
    $styles[] = [
        'selector' => ':root',
        'property' => '--theme-prefix-',
        'value'    => theme_prefix_parse_font_variant( $variant ),
    ];

    // Add css.
    foreach ( $styles as $style ) {
        $selector = is_array( $style['selector'] ) ? implode( ',', $style['selector'] ) : $style['selector'];

        $css['global'][ $selector ][ $style['property'] . 'font-weight' ] = $style['value']['font-weight'];
        $css['global'][ $selector ][ $style['property'] . 'font-style' ]  = $style['value']['font-style'];
    }

    return $css;
}

function theme_prefix_parse_font_variant( $variant ) {
    // Font weight.
    $property['font-weight'] = str_replace( 'italic', '', $variant );
    $property['font-weight'] = ( in_array( $property['font-weight'], [ '', 'regular' ], true ) ) ? '400' : $property['font-weight'];

    // Font style.
    $property['font-style'] = ( false === strpos( $variant, 'italic' ) ) ? 'normal' : 'italic';

    return $property;
}
rahulv3a commented 2 years ago

@MapSteps please consider reopening this issue.

JiveDig commented 2 years ago

Related to getting variant/font-weight to work here, I think it's worth considering a way to easily add/load other font weights, as mentioned in this thread. It's great that we let the user choose a body font weight, but it's a lot of extra code to find and load the italic version, and a heavier weight than whatever is chosen for the main font weight.