Fix for Asp.Net Optimization StyleBundle fallback
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
Website
packages
.gitattributes
.gitignore
README.md
StyleBundleFallback.sln

README.md

Style Bundle Fallback

When using Microsoft ASP.NET Web Optimization Framework there is no reliable way to target a CDN stylesheet and also provide a local fallback. There are two parts to this problem outlined below.

Style Bundle Fallback Solution

The StyleBundleExtensions.cs class provides an extension method to the StyleBundle, that injects a fallback script into the page that will load a local stylesheet when the CDN source fails. To use it, call the .IncludeFallback() extension method on the StyleBundle object. It is important to provide a class name, rule name and rule value from the stylesheet being loaded from an external CDN.

public static void RegisterBundles(BundleCollection bundles)
{
    BundleTable.EnableOptimizations = true;
    bundles.UseCdn = true;

    bundles.Add(new StyleBundle("~/bundles/bootstrap",
        "//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css")
        .IncludeFallback("~/Content/bootstrap/bootstrap.css", "sr-only", "width", "1px"));

    bundles.Add(new StyleBundle("~/bundles/bootstrap-theme",
        "//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css")
        .IncludeFallback("~/Content/bootstrap/bootstrap-theme.css", "well", "background-repeat", "repeat-x"));
}

It also determines if the stylesheet is on a CDN in another domain and provides a reliable javascript test for the resource. This should be 99% of the time, because it doesn't really make sense to load resources from a CDN on your own network, but I guess it could happen in a corporate environment. When the CDN is within the same app domain, the javascript is more robust.

  • Make sure you use a Rule Name and Rule Value that will compare accurately in all browsers. For example, an explicit width is a good choice, but font-weight is not because it may be bold or 700 depending on the browser.

  • Don't IncludeFallback more than one file per CDN bundle... it doesn't make sense, there can only be one StyleBundle.CdnPath per bundle.

  • It isn't necessary to provide class name, rule name and rule value for a fallback stylesheet coming from a local CDN.

1. Problem with the Optimization Framework

The first is a documented issue in the Optimization Framework where it incorrectly renders <script> instead of <link> when rendering the StyleBundle.CdnFallbackExpression.

The solution to this is to set the StyleBundle.CdnFallbackExpression to a javascript function that checks that the stylesheet is loaded and if not, loads the fallback from the local web server. The Optimization Framework will still output the invalid script, but it will be ignored and not cause a problem.

2. Problem determining if a stylesheet has been loaded

The second problem is generally "How to determine when a stylesheet has successfully loaded"? Some solutions I found use document.styleSheets and rules || cssRules, but this is a security violation on some browsers when the stylesheet is cross-domain. YepNope does it this way.

The solution is to inject an element into the page and apply a style from the stylesheet. If the stylesheet is loaded, the element will have the style's rules applied, if not the fallback should be loaded. You can see this method and a more robust solution for stylesheets in the domain in StyleBundleFallback.cs

Other Links