I was reading about asynchronous CSS loading
here
and I was wondering if it is possible to use that kind of behaviour in MVC5 bundles.
What I want to achieve is multiple bundled CSS files downloaded in a non-blocking way (meaning faster loading time of my page)
There's a method on the Styles helper where you can set your own tag format.
#Styles.RenderFormat("<link href=\"{0}\" rel=\"preload\" as=\"style\"/>",
"~/Path/To/My/Bundle")
For full working solution I'm using the answer I marked as acceptance to this question, but I've added one more thing to it to make it work 100%
onload="this.rel='stylesheet'"
so working example is:
C# file:
public const string StyleRenderFormat = "<link href=\"{0}\" rel=\"preload\" as=\"style\" onload=\"this.rel='stylesheet'\"/>";
cshtml file:
#Styles.RenderFormat(BundleConfig.StyleRenderFormat, "~/myCssBundleName")
Related
I have an ascx that has some CSS in it. It is possible that this ascx could be added multiple times to a page. The CSS that it uses would only need to be included once.
Is it possible to conditionally include CSS? If so how?
Is this considered bad practice?
I have an ascx that has some CSS in it... Is this considered bad practice?
Yes. Your CSS rules should ideally be defined in a separate, static css file that gets loaded only once in the header by your master page. CSS in the body is not standards compliant.
If you set up good caching rules on your static CSS files, this will significantly reduce the amount of data you pull across the wire because the CSS rules won't need to be loaded again for each page load. If you want to only include this file in the header if certain dependent ASCX files get rendered, look at Neil Fenwick's answer.
Update
For whatever reason, Neil Fenwick seems to have deleted his answer. Hopefully he won't mind my reproducing it here:
Definitely YES, it is possible.
I would recommend looking at a library like ClientDependency to manage your CSS and JS includes & dependencies.
Good examples for how to include given on ClientDependency codeplex page.
Its good practice to organise your CSS and JS dependencies so that you can assert their requirement multiple times, but only emit the dependency in the output once.
The ClientScriptManager can handle this simply by checking whether or not some particular "script" has been added. Intended for javascript, but works for anything.
if(!Page.ClientScript.IsStartupScriptRegistered("mykey")) {
Page.ClientScript.RegisterStartupScript(this.GetType(), "mykey", "<link type=\"text/css\" href=\"stylesheet.css\"/>", false);
}
You might be very interested in looking into Modernizr which allows you to do plenty of interesting test and load different resources (for example CSS) depending on test result. For example you might want to load rounded-images.css if the browser does not support border-radius etc.
Building on Neil's answer. We make use of Telerik's ASP MVC extensions to manage our JavaScript and CSS in ASP.NET MVC. It allows for "smart" inclusion of JS and CSS (even from a partial-view) preventing file duplication. It comes with other bells-and-whistles as well (like file merging and compression).
This is probably not applicable to your exact situation based on your post (raw ASP.NET), but thought I would mention it for the sake of ASP.NET MVC users looking for the same thing.
Put that in the head of the html.
<pre>
<!--[if gte IE 8]>
<link rel="stylesheet" type="text/css" href="ie8-and-up.css" /> <![endif]-->
</pre>
For more info go to: http://css-tricks.com/132-how-to-create-an-ie-only-stylesheet/
GTE means greater than.
Horrible practice. Unless that is all you do at your work since that is going to create a big workload since each css file might need to be changed in the future.
I've successfully created an mvc/razor web application that returns css files that have been parsed by razor. Each time there's a background-image I have a razor snippet that writes the URL prefix to the image file name. The CSS now looks like this:
body { background-image: url(#LookupUrl.Image("background.gif")); }
Css files now work fine and I've moved onto trying to get javascript .js files to function the same way but these aren't playing ball.
The code is identical to the css code and it successfully finds the .js file, but razor seems to parse it differently. Here's an example js file:
function testFunction() { alert('test function hit!'); }
testFunction();
Razor seems to think it's code that it should compile, and gives the error:
Compiler Error Message: JS1135: Variable 'alert' has not been declared
> Source Error:
>
> Line 1: function testFunction() {
> Line 2: alert('test function
> hit!'); Line 3: } Line 4:
> testFunction();
After renaming the same file to .css it works fine.
Is there a way of getting razor to function with .js files in the same way as it does for .css?
Here's how I registered the file handlers for razor:
RazorCodeLanguage.Languages.Add("js", new CSharpRazorCodeLanguage());
RazorCodeLanguage.Languages.Add("css", new CSharpRazorCodeLanguage());
WebPageHttpHandler.RegisterExtension(".js");
WebPageHttpHandler.RegisterExtension(".css");
The build provider is registered in PreApplicationStart via the method Haacked outlines in his blog post.
Do I need to remove a handler that mvc adds for .js files?
UPDATE 2 days on
While I got working what I wanted to get working, I would not recommend this method to others. Using Razor to parse css/javascript is flawed without the use of <text><text/> - it's the simplicity of razor using the # ampersand that messes it up. Consider the CSS3 #font-face. Razor hits the # and thinks it should use it as a function. The same thing can happen with javascript, and happened with Jquery 1.5.1.
Instead, I'll probably go back to aspx webforms for dynamic css/javascript, where there's less chance of the <% %> code blocks appearing naturally.
I couldn't understand why CSS worked while JS didn't, especially after the copy+pasted JS code worked inside the CSS file.
I used the find/replace dialogue within visual studio on the System.Web.WebPages.Razor source to search for the string '.js' within the project. There was nothing helpful there so I then went to the System.Web.WebPages project. It found a match in System.Web.WebPages.Util, which is a static class with a few helper methods.
One of those methods is 'EnsureValidPageType' and within there is a try/catch block. Inside the 'catch' block is a comment:
// If the path uses an extension registered with codedom, such as Foo.js,
// then an unfriendly compilation error might get thrown by the underlying compiler.
// Check if this is the case and throw a simpler error.
It made me believe .js has got some special built-in handler with it.
I googled for a bit, couldn't find anything, then looked in the web.config that's within \Windows\Microsoft.NET\Framework64{version}\Config.
In there is a buildProvider mapping for the extension .js to
System.Web.Compilation.ForceCopyBuildProvider
After removing this buildprovider in the website's web.config, .js files get compiled and work as they should!
I'm still not too sure what the ForceCopyBuildProvider does or is for but I wonder if it's for visual studio. Various extensions have different Copy/Ignore build providers registered.
Once again apologies for answering my own question but I hope the comprehensive(waffley) answer might help others out.
You could try using the special <text> node to indicate to the Razor parser to treat the content literally:
<text>
function testFunction() { alert('test function hit!'); }
testFunction();
</text>
The default Razor parser uses the HtmlMarkupParser to handle the markup components of your template. There isn't currently any alternative parsers that support other markup languages (which you would need to treat the javascript code language as). If you did create a new markup parser, I would imagine it would be quite difficult to separate the code and markup (i.e. the C# and the Javascript).
What you could do, is use the <text></text> wrapping elements to enforce the parser switches to markup mode when that section of the template is reached, e.g.
<text>function testFunction() { alert('test function hit!'); }</text>
It's not pretty, but it should do the trick.
Friends, I am willing to follow the rules of the W3C where it is recommended that javascript and CSS files should be in individual files and not within the page.
Good, following this rule, and not wanting to overload the master page, I would like to embed the dependencies dynamically. So how could I insert the libraries dynamically? I think the bigger problem is the Ajax requests.
Example:
<script type="text/javascript" src="http://sstatic.net/so/js/master.js?v=6523"></script>
I tried using the JavascriptResult, but he writes the content on the page, and do not run as "Stream."
Any help is welcome. Thanks
If I understand correctly the problem, you want to add script files dynamically to the page.
You can try jQuery load function, that can parse for you the result in very intuitive way.
One SEO advice we got was to move all javascript to external files, so the code could be removed from the text. For fixed scripts this is not a problem, but some scripts need to be generated as they depend on some ClientId that is generated by asp.net.
Can I use the ScriptManager (from asp.net Ajax or from Telerik) to send this script to the browser or do I need to write my own component for that?
I found only ways to combine fixed files and/or embedded resources (also fixed).
How about registering the ClientIDs in an inline Javascript array/hash, and have your external JS file iterate through that?
Spiderbots do not read JavaScript blocks. This advice is plain wrong.
Some javascript can break W3C validators (and possibly cause issues with some spiderbots)
You can reduce this by placing this code around your javascript:
< !-- no script
... your javascript code and functions ...
// -->
Note: remove the space between "<" and "!" as it seems to comment out the example here :-)
I know that you can apply CSS in order to style objects in Flex using the StyleManager:
http://livedocs.adobe.com/flex/3/html/help.html?content=styles_07.html
You can also load compiled CSS files (SWFs) dynamically:
http://livedocs.adobe.com/flex/3/html/help.html?content=styles_10.html
However, I'm dynamically creating my CSS files using a web GUI and a server-side script.
If the CSS is changed, then the script would also need to compile the CSS into an SWF (which is not a viable option). Is there any way around this?
In this comment to an issue related to this in the Adobe bug tracker T. Busser is describing what might be a viable solution for you:
"I've created a small class that will 'parse' a CSS file read with an
HTTPService object. It takes apart the
string that is returned by the
HTTPService object, break it down into
selectors, and create a new
CSSStyleDeclaration object for each
selector that is found. Once all the
properties are assigned to the
CSSStyleDeclaration object it's added
to the StyleManager. It doesn't
perform any checks, you should make
sure the CSS file is well formed, but
it will be sufficient 99% of the time.
Stuff like #font, Embed() and
ClassReference() will hardly be used
by my customers. They do need the
ability to change colors and stuff
like that so they can easily theme the
Flex application to their house
style."
You could either try to contact this person for their solution or alternatively maybe use the code from this as3csslib project as a basis for writing something like what they're describing.
You can also implement dynamic stylesheet in flex like this . Here i found this article :
http://askmeflash.com/article_m.php?p=article&id=6
Edit: This solution does not work. All selectors that are taken out of the parser are converted to lowercase. This may work for your application but it will probably not...
I am leaving this answer here because it may help some people looking for a solution and warn others of the limitations of this method.
See my question: "Looking for CSS parser written in AS3" for a complete discussion but I found a CSS parser hidden inside the standard libraries. Here is how you can use it:
public function extractFromStyleSheet(css:String):void {
// Create a StyleSheet Object
var styleSheet:StyleSheet = new StyleSheet();
styleSheet.parseCSS(css);
// Iterate through the selector objects
var selectorNames:Array = styleSheet.styleNames;
for(var i:int=0; i<selectorNames.length; i++){
// Do something with each selector
trace("Selector: "+selelectorNames[i];
var properties:Object = styleSheet.getStyle(selectorNames[i]);
for (var property:String in properties){
// Do something with each property in the selector
trace("\t"+property+" -> "+properties[property]+"\n");
}
}
}
You can then apply the styles using:
cssStyle = new CSSStyleDeclaration();
cssStyle.setStyle("color", "<valid color>);
FlexGlobals.topLevelApplication.styleManager.setStyleDeclaration("Button", cssStyle, true);
The application of CSS in Flex is handled on the server side at compilation and not on the client side at run time.
I would see two options then for you (I'm not sure how practical either are):
Use a server side script to compile your CSS as a SWF then load them dynamically.
Parse a CSS Style sheet and use the setStyle functions in flex to apply the styles. An similar example to this approach is the Flex Style Explorer where you can check out the source.
Good luck.