Auto Page-Specific Css with ASP.NET MVC
As a developer who wants to be conscious of good client-side practices, I’m always looking for good ways to keep my Css separate from my Html. When there are page-specific css styles to apply, it is often tempting to add them to the page itself. It works, it's not evil but I wouldn’t recommend it. Here’s an easy trick I have used on several projects to make it easy to target page-specific design problems in a global css file without worrying about adversely affecting other pages.
Let’s start with what we want the css to look like. Let’s setup three scenarios. First, let’s say we want normal paragraph text to be a dark color, but not black. Second, we want any paragraph text inside and article tag to be black. Third, we want all paragraph text for the url /home/index (and we’ll assume that the default routing is setup) to be white. I want my css to look something like this.
p
{
color: #333;
}
article p
{
color: #000;
}
body.home_index p
{
color: #FFF;
}
The first two style rules are generic. They are meant to target every page. The last rule is specific to a particular page.
If you are using master/layout pages with ASP.NET MVC, you probably can’t change the body tag on a per-page basis in the view file because the body tag will probably be in the layout page. The first step to solving this is to add a reference to a variable on the ViewBag in the layout page, like the following:
<body class="@ViewBag.PageClass">
If you are familiar with ASP.NET MVC and ViewBag, you know you could now either supply that value in the code in the view or in the controller action. Both would work fine, but that would be annoying because you would have to repeat the (admittedly simple) logic for inserting that bit. Enter a controller base class.
public class CustomBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
string pageClass = filterContext.RouteData.Values["controller"].ToString()
+ "_" + filterContext.RouteData.Values["action"].ToString();
ViewBag.PageClass = pageClass.ToLower();
}
}
The OnActionExecuting method on Controller executes before the action on a controller executes. This bit of code uses your routing setup to create a per-controller-action pair css class name and assigns it to a variable in the ViewBag which, as was seen above, you can use in your pages. Now change your controller to inherit from this fancy new controller you have created, build, and run the app. The finished result?
<body class="home_index">
Simple yet effective. You can expand this to pay attention to areas as well, or tweak in a different direction to suit your needs. Good luck and style away!