Anyone who has tried to brand their SharePoint sites has probably encountered the 5 stages of grief when learning about the core.css:

  1. Disbelief - “They couldn’t have possibly designed it this way; I must be missing something!”
  2. Anger – “This is ridiculous! What a waste of time and money!”
  3. Bargaining – “If I can get this to work the way I want, I promise I will love SharePoint forever.”
  4. Depression – “Maybe I’m not cut out for this SharePoint stuff. I should do something else. I wonder if there are any openings at Best Buy.”
  5. Acceptance – “Okay, I just won’t brand my site the way I wanted to do it.”

Essentially, Microsoft (in it’s infinite wisdom) has most of the styles, for any particular template, stored in the core.css.

There has been plenty of discussion on how one might modify those styles. Heather Solomon is certainly the resident expert on it. When diving in you might start to read about things like “ghosted” and “unghosted” or “customized” and “uncustomized”.

The reality is that you may only want to make one minor change to the core.css and not have the whole thing be sent into the file system in a “customized” state. Or maybe you’re a purist (read: anal-retentive) and you just don’t like the idea of your core.css being stored on the file system.


Understanding that a value in a stylesheet takes precedence in the order it was applied (hence the name “cascading”) you might start to think:

“Gee, if I create a new style in a new stylesheet with the same name of the one stored in the core.css, it should overwrite that style and all will be wonderful again!”

A-hem…not exactly.

By it’s very nature, core.css is designed to load after any other specified stylesheet. Therefore, no style can be overwritten because core.css is ALWAYS applied last.

CURSE YOU MICROSOFT!

So to change this behavior, we must hijack the rendering of the CSSLink server control in SharePoint.

CSSLink is used in order to load a specified stylesheet (using the DefaultUrl property). This will return all of the system stylesheets along with the path of the stylesheet you specified. All of this will be in order (yep, you guessed it) with the core.css sheet specified last.

The class that I built is rooted in the work of Michael Hofer and CleverWorkarounds.

This class creates a server control that is to be used in replace of CSSLink and is called EnhancedCssLink. I would read Michael Hofer’s blog on how you might add this class to your SharePoint site (build a .dll, mark it as safe in your web.config, deploy it to your SharePoint GAC or bin folder, etc.) If you can’t find out how to do it there, Google it man!

Michael Hofer’s class puts the core.css last in the order, which can be problematic. CleverWorkarounds improved on this idea by switching the core.css with a specified .css sheet. Ultimately, giving the specified stylesheet the highest priority. Cool!

I expanded on these two ideas by allowing the user to specify multiple stylesheets (separated by a comma). The DefaultCss property is now named “CSSPath”. Here’s an example on how to use it:

<PublishingEnhancements:EnhancedCssLink runat=”server” CSSPath=“../../_styles/master.css, ../../_styles/webparts.css”/>

This will now return the system stylesheets in the proper order with the specified stylesheets loaded last.

Finally, here is my code for the EnhancedCssLink class:

 

//Publishing Enhancements

namespace PublishingEnhancements

{

public class EnhancedCssLink : CssLink

{

public EnhancedCssLink() : base() { }

private string CSS;

public virtual string CSSPath

{

get

{

return CSS;

}

set

{

CSS = value;

}

}

protected override void Render(System.Web.UI.HtmlTextWriter output)

{

// Let base render the stylesheets

StringWriter sw = new StringWriter();

base.Render(new HtmlTextWriter(sw));

string renderedOutput = sw.ToString();

if (this.CSS == null) {

output.Write(renderedOutput);

}

else

{

// Split the styleSheets into an array

string[] styleSheets = renderedOutput.Split(new char[] { ‘\n’ }, StringSplitOptions.RemoveEmptyEntries);

if (styleSheets.Length == 0)

{

output.Write(renderedOutput);

}

else

// Render the system stylesheets, then render any specified stylesheets after that

{

string[] customStyleSheets = this.CSS.Split(new char[] { ‘,’ }, StringSplitOptions.RemoveEmptyEntries);

output.Write(string.Concat(styleSheets));

for (int i = 0; i < customStyleSheets.Length; i++)

{

output.Write(“<link rel=’stylesheet’ type=’text/css’ href=’” + customStyleSheets[i].ToString() + “‘ />”);

}

}

}

}

}

}