Using ACF and L&L to update inline styles

Problem

I use ACF a lot to manage my theme, and I have been wondering how to dynamically update things like the CSS background property, which I use to apply a background image to banners.

Solution

I finally realised I could do this using inline styles updated by L&L template logic since I can’t use logic inside an L&L style template.

I have this working, but it does get tricky since all the logic needs to sit inside the HTML style attribute. I followed @benjamin’s advice in this thread, which was helpful. :slight_smile:

Here is the logic I am using to specify background properties for banners:

<div class="sim-section sim-banner {Field sim_banner_type}" style="{If field=sim_banner_background_type value=none}background: none; {Else field=sim_banner_background_type value=color /}background: {Field sim_banner_background_color /};{Else field=sim_banner_background_type value=image /}background: url({Field acf_image=sim_banner_background_image field=url /}) {Field sim_banner_background_repeat /} {Field sim_banner_background_attachment /} {Field sim_banner_background_position /}{/If}">

(This is hard to read because of the syntax used inside attributes)

View Website Demo

Improvements

I am pretty happy with this solution, but one major downside of inline styles is that they don’t support CSS media queries, so currently, I am loading a desktop-sized image for mobile, which will slow down the page load.

Here are some solution options I am considering:

1. L&L Mobile Detect

One hack I thought of is to create a separate mobile-optimised image in ACF and use the Mobile Detect | Loops & Logic tag with an <IF> statement to load the right-sized image for the device. I’m unsure if using Mobile Detect is the right way to go here because it has limitations and will also increase page load times.

2. CSS background with image-set

The CSS background property can include multiple images for different pixel densities. However, it doesn’t solve my problem, as browser support for pixel widths (similar to media queries) is still evolving.

It’s explained well in this article but gets kind of complicated:

3. HTML picture

I’ve seen a few articles advising the <picture> element is well-supported by browsers now and can replace older approaches like CSS background with more flexibility. This sounds like a good option, but I have never used it before, and it will take some work.

Anyway, I will continue to research this, but if anyone else has thoughts, I would like to hear them. :slight_smile:

Interesting, thanks for sharing! I haven’t played around much with SCSS/SASS but I know there are some extra options there, which might be useful in this case. Like apparently conditional logic exists to an extent.

Your approach seems like it’d work great if you have a single div that needs to be styled, but you’re right that the inline CSS approach is tricky, particularly if you’d want to apply the same color to multiple elements on a page, for example. It’d be a lot of redundant conditional logic.

I think the way I’d approach this would be to set a sass variable and then refer to it in my template’s style tab with SASS’s $my-variable-name syntax.

Template:

<Set sass=dynamic-background>
  <Switch field=sim_banner_background_type>
    <When value=none />
      none
    <When value=color />
      <Field sim_banner_background_color />
    <When value=image />
      URL("<Field acf_image=sim_banner_background_image field=url />") <Field sim_banner_background_repeat /> <Field sim_banner_background_attachment /> <Field sim_banner_background_position />
  </Switch>
</Set>

<div class="sim-section sim-banner sim-background {Field sim_banner_type}">

Style:

.sim-background {
  background: $dynamic-background;
}

I haven’t tested this myself but I imagine this approach would work and would be more performant in situations where the styling needs to apply to multiple elements and it’s also a bit easier to read.

Thanks for the info, there might be some options there but I will have to dig into what’s possible with SCSS.

I should have mentioned that the banner feature uses an ACF repeater to get the banner options. I think the logic load is okay for now, but this could become an issue as I add more customisation options.

@benjamin, could you please advise why we can’t use logic inside a style template? Is it possible this could be added in the future? Maybe there are good reasons for preventing this. :thinking:

Usually, I would swap classes in and out of the HTML to achieve a different style, but the CSS background property needs a URL for the image, and I can only get this from within an HTML template.

Also, sometimes updating CSS property values directly using inline styles is easier than creating many new classes.

For example, these controls are for the flexbox widths:

From my understanding, it’s simply an issue with mixing languages and syntax. The L&L language shares a syntax with HTML, so they can both be parsed the same way in a template. I imagine trying to parse HTML and SASS at the same time would result in conflicts between the two where their syntaxes overlap.

1 Like

Since Sass/SCSS already has conditional logic built in, it sounds like you’re moreso looking for a way to refer to field values in your Style post. Currently that requires defining sass variables in the template, which you can’t do on a Style post, meaning that you can’t have a stylesheet from L&L that gets automatically rendered on certain pages while also interacting with that page’s custom fields. I don’t see us extending the Sass language to dynamically refer to fields, but I could imagine it being technically possible to allow templates to run on Style posts or to load template/styles in other styles, similar to what you can do with templates using the Template tag.

1 Like

@benjamin, thanks for the info. I agree it would not make sense to implement features that break the template’s syntax.

The feature I ultimately want is an easy way to provide ACF values as CSS variables in the style template. This would enable some nice solutions like grabbing a URL for the CSS background property and dynamically updating CSS values from an ACF UI.

I imagine I can find a PHP solution for this, but I would prefer a ‘low code’ approach using L&L. I’ve hardly used any PHP so far to build Simplicty Theme. :slight_smile:

I had a closer look at this approach, and it does allow the use of ACF values in the style sheet and the proper use of CSS structure, so I’ve used it to replace my inline styles solution.

Having access to media queries makes it easy to implement responsive images for the background property. Simply set the image sizes (small, medium, large) as SASS variables and follow the instructions here:

However, the solution change required ditching my ACF repeater + ID solution for controlling the banner UX because the repeater loop overwrote the SASS variables and caused styling conflicts.

The inline styles approach had one significant advantage: it printed out the style for each loop/banner, and the styles did not interfere with each other.

The SASS variable names must be unique for each loop/banner, so I created separate ACF groups and Templates (Banner 1, Banner 2, Banner 3 etc.) to get everything working reliably. The code quality is much better, but I still have a maintenance issue. :thinking:

Maybe there is a way to manage SASS variables using ACF and L&L, so they don’t have to be explicitly stated for each instance of the loop/banner. Returning to the ACF repeater with ID solution would be nice, as that worked great, and I would have used it a lot. :slight_smile:

To cap this off, I now have multiple banners working on the same page using a single template with the ACF repeater + ID solution. :smiley:

It would take a while to write out the full solution, but it’s possible to have unique SASS variables for each loop item using Switch and When.

When placing more than one banner on the same page, you give each one a local variable that instructs the template to use a different set of variable names.

After that, it’s just a case of creating some unique CSS classes and ensuring defaults exist for all the SASS variables, so the template doesn’t crash when some are not used.

This might be a good candidate for the template gallery if it proves to be robust. :slight_smile:

1 Like

Glad you’ve got this working nicely!

In the past when I’ve needed unique variable names for each loop item, I’ve done something like this:

<Set name="variable-{Get loop=count /}">some value</Set>

Not sure if that applies in your particular situation, but if you don’t need granular control over your variable names, this is a great way to handle that dynamically instead of manually.

This was one of the first things I tried, but I could not get it to work with SASS variables even when using your exact syntax:

<Set sass="banner-{Get loop=count /}-title-font-size"><Field name=title_font_size />rem</Set>

Either way, I’m not sure it helps a lot because, as I understand it, I would need to change variables and class names on each loop to ensure each banner has its own styling.

Currently, my classes look like this:

Banner One:
.sim-banner.one .sim-banner-content :is(h1, h2, h3, h4, h5, h6) {
font-size: $banner-one-title-font-size;
}

Banner Two:
.sim-banner.two .sim-banner-content :is(h1, h2, h3, h4, h5, h6) {
font-size: $banner-two-title-font-size;
}

It would be great to fully automate this using L&L and SCSS logic, as the solution will work for any feature in an ACF repeater with styling controls. :slight_smile:

1 Like

I just updated my template above to account for this based on some new info I learned yesterday. URLs in CSS/SCSS are strings, which means they need to be quoted. This means you need to use the type attribute to specify this.

<Set sass=background_image type=string><Field background_image></Set>
.background {
  background: url($background_image)
}

If you wanted to use Switch/When like I showed in my reply above, then you can’t sure the type attribute and would instead just need to add the quotes in manually around "<Field background_image>"

Ultimately I feel like the solution here would be to use L&L to create a dynamic stylesheet with SCSS variables in the document head, but as you found out here, apparently that’s not how WordPress works. Bummer.