News:

Want to get involved in developing SMF, then why not lend a hand on our github!

Main Menu

How to force css reload?

Started by FragaCampos, July 19, 2021, 02:29:00 PM

Previous topic - Next topic

FragaCampos

Hi there.

I have a theme css file which contains two image links to background images in my forum. Now and then, I change those images and the links also change in the css.
The problem is that the css file is cached by web browsers and my forum users don't always see the changes in those images.

I've searched here at SMF and elsewhere for solutions on how to force a css reload and I found that it can be done via .htaccess
I didn't find a catch all solution, but I ended up with this one, which seems to force a reload every 24h:
<IfModule mod_headers.c>
    <FilesMatch "\.(css|js)$">
          Header set Cache-Control "max-age=86400"
    </FilesMatch>
</IfModule>



Is this ok? Does it cause any undesirable side effects?

Regards.

Gary

You can force it to reload by simply pressing Ctrl + F5.

For your users, just tell them to do the same.
Gary M. Gadsdon
Do NOT PM me unless I say so
War of the Simpsons
Bongo Comics Fan Forum
Youtube Let's Plays

^ YT is changing monetisation policy, help reach 1000 sub threshold.

Sir Osis of Liver

Try this -

[

# NEVER CACHE
<FilesMatch "\.(txt|htm|html|php|css)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</FilesMatch>


Ashes and diamonds, foe and friend,
 we were all equal in the end.

                                     - R. Waters

FragaCampos

I had seen this here in the forum, but I thought that it's more heavy on the server (although the css file size is near negligible).


Quote from: Sir Osis of Liver on July 19, 2021, 09:39:59 PM
Try this -

[

# NEVER CACHE
<FilesMatch "\.(txt|htm|html|php|css)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</FilesMatch>




Sir Osis of Liver

Shouldn't be a problem unless you have a huge amount of traffic.  You can always limit it to just css files.
Ashes and diamonds, foe and friend,
 we were all equal in the end.

                                     - R. Waters

Chief of Nothing

Quote

# NEVER CACHE
<FilesMatch "\.(txt|htm|html|php|css)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</FilesMatch>


Several of those directives don't go together, certainly no-cache and no-store are at odds with each other, and private and no-store are at odds with each other

OP, if you have Etags enabled in Apache (I think last-modified also works) you can simply:


<FilesMatch "\.(txt|htm|html|php|css|js)$">
Header set Cache-Control "no-cache"
</FilesMatch>



The no-cache header, despite it's name means the resource is cachable but the browser needs to revalidate it's cached copy against the server everytime.

I'm not totally in tune with Apache as I started using Nginx quite some time ago but in Apache the Etag header is set in either httpd.conf or in .htaccess if you don't have access to httpd.conf. I believe it's set like this:


# Create the ETag (entity tag) response header field
FileETag MTime Size


drewactual

don't know why a 'dummy timestamp' hasn't been mentioned yet...

simply add a pseudo time stamp to the file... ergo "my.css" is altered to "my.css?v=today ....

that is one way to do it...and it works.. but.. it won't allow the browser to cache the file, or better said it can confound some browsers whether it should be cached or not...

the "BEST" way to do it, if you're using apache, is to leverage mod_expires... it's an addition to the httpd or the htaccess as such:


<IfModule mod_expires.c>
  ExpiresActive on
  ExpiresByType text/css "access"
</IfModule>


boom, done.

but the simplest and most assured way to do it is to simply change the name of the file... ergo: my.css, then my2.css, then my3.css, ect... meaning, every time you change the css, change the name of the file called in index.template.... this is pretty much fool-proof...

if you really want to bang things up- you can run a little php random script as i have on cfb51.com... there are other and maybe better ways to do what you're doing and causing yourself issues, in other words.

Chief of Nothing

There is already a query string "version" appended to .js and .css files when a page is loaded, but in SMF 2.0.x judging by what I see it appears to be a fixed string so not effective for cache busting. I haven't looked at the code for 2.0.x (I'm playing around with 2.1) so I don't know 100% for certain but to put your own "version" query string in might possibly require code changes.

Putting the version in as part of the filename itself is what a lot of sites do, as (historically) there was issues with the query string method and caching (which I believe is no longer the case for browsers)  but as you mentioned that requires changing the code in the template, something the OP may be reluctant to do keep doing.

Setting the script or css file to expire immediately with the Expires header will work but then aren't you fetching the file brand new every single time a page loads it (I haven't got Apache set up right now to test that)? That could be a lot of wasted bandwidth for a file that the OP changes "Now and then".

FragaCampos

That's why I preferred the version with "max-age=86400", because I can change that to a higher value, say one week.

Maybe asking to the webserver I get a more conclusive answer.


Quote from: Chief of Nothing on July 20, 2021, 01:38:47 AM
Setting the script or css file to expire immediately with the Expires header will work but then aren't you fetching the file brand new every single time a page loads it (I haven't got Apache set up right now to test that)? That could be a lot of wasted bandwidth for a file that the OP changes "Now and then".


drewactual

the thing about cache's is you don't and can't control them all... you will have a sense of ownership and control leveraging the tools we've discussed, but, you aren't going to stop some switches routers and hubs from straight up caching what they want to cache.  it's just the nature of things- as a for instance, verizon (just yanking them from the box of all of them) may want to present pages faster than their competitors (which they do), and, instead of doing it how they elude, they do it by caching... and when it's cached? it stays there like glue and doesn't give one care what directives you prescribe.

cache busting is a big business because of this.  it seems like a really good idea to control the directives through expires and even etags, but... you only vaguely control what you 'think' you control.

so... and i don't post here that often anymore because of situations just like this one- as most will gleefully point you to a modification and suggest you use the admin interface to manage it- all when it requires a couple lines of code to do what you need.

if i were you and i'm not you, but if i were and wanted to rotate or change an image, and realizing the images themselves are also cached outside of your control (which disallows you to effectively use the same image filename and just swap the image in and out), i would add a simple INCLUDE (not a require) code in your index.template for the theme in question... this is how i'd do it without knowing the structure of your website... :

1st- I'd make a new file and rest it in your theme's folder... name it 'image-change.php' for the purpose of this conversation... within it, i would have a tiny bit of markup, such as a div# and perhaps a div.class- just in case you ever want to float some text or a box, or an image over an image type thing in it- but again, this is just me... but the important part would be the image you will be swapping from time to time. plop it in there between whatever markup you deem necessary. 

2nd- i'd open up the index.template, and in the area of your image i'd add an INCLUDE (not a require) something like:include ('.././image-change.php');

3rd- i'd cruse over to your theme's css file, and i'd markup the DIV where this image is to appear, and i'd affix a BACKGROUND image... this is the fail safe- this ensures if the php file fails to load for any reason, that area isn't blank.. it has an image that appears to a user like any other image...

4th- give her a rip- save all, and load the page... what you should see is the include rendering the image you told it to in the image-change.php file, but if it doesn't? if you typed up an error in your code? because you used an include instead of a require, it'll load up the background image prescribed in your css and the user is none-the-wiser. 

5th- when you want to change the image, you change it in the image-change.php instead of the css or the index.template (which 'should' be left as virgin as possible or within reason).....

using that method to achieve your goal will make for certain the image you wish to render is rendered to the user... the ONLY caveat is using something like OPCache, in which case you'll need to expire the image-change.php manually each time you change it.  not a big deal.  i'd even rec you 'include' an html page instead of php, but then we're back to cache's... so... stick with the .php file include...

Chief of Nothing

Generally speaking, a switch, router or (horrors) a hub doesn't cache web content. Yes, there is some enterprise stuff that has that capability that you might find in a corporate style workplace but you won't find it at the consumer level and I seriously doubt you'd find it at any ISP or transit provider level. For the latter two they'd use web proxies to do the caching but even these are more and more falling out of favour with CDN's becoming more and more popular.

I'm not saying that there isn't rouge or misconfigured web proxies out there but any cache is required to honour the Cache Control directives so setting them is all the OP should need to do. I'd also imagine that unless the OP is running a super popular site that rivals something like FB for traffic that any content from his site that was cached on a proxy would be expelled in pretty short order to make room for content that is getting way more hits.

Your image-change.php method is also a good one.

OP, there is a online tool that you can use to check your cache related headers: https://redbot.org/. I haven't used it so I don't know how good it is.

Adrek

I remember that I used to change numbers after ? in index.template.php
echo '
<link rel="stylesheet" type="text/css" href="', $settings['theme_url'], '/css/index', $context['theme_variant'], '.css?fin20" />';


and that forced browsers to download fresh CSS

also there can be used some part of time() output
Polskie wsparcie SMF na simplemachines.org

the simplest solution is most likely the right one

Advertisement: