29

I have just spent half a day quietly going mad.

I'm making changes to my classes in the Site.css file and they were not being reflected in the site being developed on my machine. Because I'm learning my way through jQuery and playing with addClass and removeClass and I'm creating the parameters for those calls dynamically, I was sure the problem was in my implementation.

Turns out the CSS file was cached in the browser and all I had to do was refresh it...

Is there a way to force a refresh (preferably only during debug I guess)?

GilShalit
  • 6,175
  • 9
  • 47
  • 68

13 Answers13

60

A popular way of "cache-breaking" is to append a parameter to your css source. Typically a timestamp is used. I prefer the "file last modified" time, ie. filemtime() in PHP. I'm sure there's an asp.net function that would give you that.

Then your CSS tag becomes:

<link rel="stylesheet" type="text/css" media="screen" href="/main.css?123456789"/>

with the query parameter changing whenever the CSS file is updated.

zombat
  • 92,731
  • 24
  • 156
  • 164
21

Press CTRL+F5 to hard-refresh everything on your webpage including scripts and stylesheets.

Additionally, you can incorporate the stylesheets to be served from a dynamic server page [php/asp.net] and the Response.Expires = -1 which will force the client to load the css on every HTTP-GET request explicitly. You can also do this in your webserver settings for CSS mime types.

this. __curious_geek
  • 42,787
  • 22
  • 113
  • 137
  • @Mark: This has always worked for me. It is same across all browsers. – this. __curious_geek Aug 06 '09 at 16:14
  • This works to force a file update, to avoid the cache, but it isn't a permanent solution for your users. The last update unix time on the file last modified time appears to be a good solution. – Luke Jul 30 '14 at 13:55
  • In Chrome/Windows, you can hit F12 to open the Developer window. The return to your page tab and RMC the Reload (circle arrow) icon and select "Empty Cache and Hard Reload". Then close the Dev window. Vastly easier than going to Settings & deleting the cache from there. – dlchambers Apr 08 '18 at 23:35
12

I use this trick:

<link rel="stylesheet" type="text/css" href="cssfile.css?t=<%= DateTime.Now.Ticks %>" media="screen" />
Max
  • 2,529
  • 1
  • 18
  • 29
  • 1
    I have a strange behaviour on production server. The produced html has this: . This is only for stylesheets - scripts work fine. Any suggestions? – Muxa May 21 '11 at 22:42
  • 9
    The problem with this answer is that it will ALWAYS force your clients to download your stylesheet - even if the stylesheet hasn't changed on the server. The accepted answer is better because the stylesheet will only be re-downloaded by clients when it has been modified. – Ian Kemp May 09 '13 at 09:24
  • @Muxa Did you find any solution? I have the same problem – Oliver Oct 15 '18 at 15:08
  • You can write it like this: href="css/style.css?t=<%= "" + DateTime.Now.Ticks %>" – raven_977 Oct 01 '20 at 06:29
8

For ASP.NET, the code behind (you can put this in a utility class or master page):

public static string GetTimestampedUrl(string virtualPath)
{
  var realPath = HostingEnvironment.MapPath(virtualPath);
  var file = new FileInfo(realPath);

  return VirtualPathUtility.ToAbsolute(virtualPath) + "?" + file.LastWriteTime.ToFileTime();
}

And then in your page:

<link href="<%= GetTimestampedUrl("~/screen.css") %>" rel="stylesheet" type="text/css" media="screen" />
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
  • I like your solution, although it doesn't address the problem for any static .html files, only as?x files. Interesting side note about this: if you try to implement the above code as an extension method for MasterPage or Page then it fails. But if you create a base class for your pages and add it there, it works fine. – jrichview Aug 24 '16 at 15:14
  • One other edge case problem: if you have any code that dynamically modifies the controls collection in the header, it will throw HttpException 80004005 "The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>)." – jrichview Aug 24 '16 at 18:29
  • 1
    Using your above method, you could create a base class for your Page and call the following method from an OnLoad() override: 'code' private void SetHeaderTimestamps() { HtmlHead head = (HtmlHead)Page.Header; foreach (System.Web.UI.Control cntl in head.Controls) { if (cntl is HtmlLink) { HtmlLink cssTag = (HtmlLink)cntl; cssTag.Href = Utility.GetTimestampedUrl(cssTag.Href); } } } – jrichview Aug 24 '16 at 18:51
3

One trick is to add a QueryString parameter in the link to your stylesheet

What does '?' do in a Css link?

Community
  • 1
  • 1
Jason
  • 86,222
  • 15
  • 131
  • 146
2

I'm not sure about all browsers, but in IE8 you can use the developer tools...

Go To:

Tools -> Developer Tools (F12)

Then (while on your page) inside the Developer Tools:

Cache -> Always Refresh From Server

Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
2

This is a classic problem. You have a lot of solutions available:

  1. Probably the easiest way is to configure your webserver to server CSS files as never-cache/expire immediately. Obviously you wouldn't want this on a production environment. With IIS, this is very easy to do.
  2. Add a random value to the name of the file you're including, e.g. Site.css?v=12. This is what SO does for their includes. I do this in house so that on the development machine, the parameter changes each time (a guid) the file is served, but when deployed it uses the svn version number. A little trickier but more robust.
  3. Many, many more I'm sure
Michael Haren
  • 105,752
  • 40
  • 168
  • 205
2

My approach is using the “querystring changing” method to bypass caches (even in browser and proxy servers). Since I’m using Master Pages I maintain the link to CSS as usual like but adding an ID (named here as cssStyleSheet):

<head runat="server">
<link id="cssStyleSheet" href="~/Styles/Default.css" rel="stylesheet" type="text/css" />

Then at code behind I implemented at Page_Load this line of code, adding a quesrystring like “?t=5343423424234”.

Protected Sub Page_Load(…)

    If IsNothing(Application("CSSTicks")) = True Then
        Application("CSSTicks") = DateTime.Now.Ticks
    End If


    cssStyleSheet.Attributes("href") = cssStyleSheet.Attributes("href") & "?t=" & Application("CSSTicks")

End Sub

Why is that? At HTML code, some designer could change the CSS file as easy, no interfering at some “difficult” code. Using an Application variable I avoid spending bandwidth from my servers and also from customer perspective (like using mobiles).

If new application is deployed, the Application variable is reset automatically and a “new” version of CSS if downloaded to browser (even through proxies).

2

For Wordpress users, below is the code

<link rel="stylesheet" href="<?php echo get_bloginfo('stylesheet_url')."?d=".date( 'Ymd', time()); ?>" type="text/css" media="screen" />

Or better one

<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); echo '?' . filemtime( get_stylesheet_directory() . '/style.css'); ?>" type="text/css" media="screen, projection" />

Cheers!

foxybagga
  • 4,184
  • 2
  • 34
  • 31
1

The easiest way is to disable caching in your browser. If you can't or don't want to do this, you can press ctrl+f5.

Your server or asp application might be caching, too. You can disable this in the web.config or you can restart the development server to make sure the latest version of your file is shown to the user.

Scharrels
  • 3,055
  • 25
  • 31
0

Are you keeping your browser open between your changes? Often simply closing all browser windows between making changes to your CSS file will tell the browser to download a new copy.

phairoh
  • 10,485
  • 4
  • 23
  • 18
0

To further Ian Kemp's answer which utilises the LastWriteTime of the style sheet in question, I have written an MVC helper to output the <link> tag with the cache-busting parameter built in.

The Code

public static class CssLinkHelper
{
    public static IHtmlString StyleSheet(this HtmlHelper helper, string stylesheetname)
    {
        // define the virtual path to the css file (see note below)
        var virtualpath = "~/" + stylesheetname;
        // get the real path to the css file
        var realpath = HostingEnvironment.MapPath(virtualpath);
        // get the file info of the css file
        var fileinfo = new FileInfo(realpath);

        // create a full (virtual) path to the css file including a cache busting parameter (e.g. /main.css?12345678)
        var outputpath = VirtualPathUtility.ToAbsolute(virtualpath) + "?" + fileinfo.LastWriteTime.ToFileTime();
        // define the link tag for the style sheet
        var tagdefinition = string.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />", outputpath);

        // return html string of the tag
        return new HtmlString(tagdefinition);
    }
}

Usage

@Html.StyleSheet("main.css")

Output

<link rel="stylesheet" type="text/css" href="/main.css?131393346850223541" />

Note

In case you're wondering about the var virtualpath = "/~" + ... part and thinking, why not just pass it in as "~/main.css"? I have implemented this function this way because all my css files are in a common folder (/assets) and the helper will prefix my output with the common folder name i.e. /assets/main.css?131393346850223541

Community
  • 1
  • 1
Dave Becker
  • 1,433
  • 1
  • 12
  • 24
0
<link href="~/css/Style.css?t=@DateTime.Now" rel="stylesheet" />

I used this simple trick using C# Date Time.