posted by: Ralf Rottmann | posted @ Wednesday, September 12, 2007 5:18 PM | View blog reactions

I have been playing with "content publishing" engines for a couple of years. Most of them were based on the LAMP technology stack: Linux, Apache, MySQL and PHP. My personal blog has been driven by Textpattern for over a year and my teams has used the Exponent Content Management System to create websites and allow customers to change content on the fly.

In my professional life I am in charge of designing standard software solutions for large enterprises and almost solely deal with .NET and Java. Therefore it's only been a matter of time and I recently migrated my blog to a more robust stack which also allows me to extend it using C#.

After conducting some research I decided to go for Subtext, a free open-source blogging engine written to run on Microsoft Internet Information Server and currently supporting ASP.NET 2.0. Subtext installation worked like a charm, following the simple installation steps provided in the online docs. Working with Subtext was pure fun from installation, via customization to publishing my first post via Windows Live Writer. From my personal perception Subtext is better than all other engines I have been using so far. It's speedy, it's clean and because it's ASP.NET it can be easily extended.

The only thing that is currently behind is the available documentation. This, however, is a real problem when you want to start skinning Subtext to give your blog a personal look. In addition the programing model of ASP.NET is very different from PHP so it's not all that easy to intuitively gather the big picture.

While I can in no way provide a full Subtext documentation, I decided to post my experiences during the creation of the skin you're currently watching (unless you read through a syndication service). Please note that the content which follows might contain errors or misconceptions and should not be considered as official Subtext documentation. It's provided "as is" and hopefully gets you started.

Before we start a word on tools: I am using Dreamweaver CS3 for most of my web design work so most of the screenshots depict Dreamweaver in action. Feel free to use your tool of choice! Along with Dreamweaver I heavily use Firebug, a plug-in for the Firefox browser which lets you inspect any HTML document. I highly recommend to get Firefox and Firebug before you start creating your own skins.

This introduction is based on the current version of Subtext which is 1.9.5.

Phil Haack project lead for Subtext has a good introductory post about Subtext skinning which you might want to read first. Let's recap the essentials:

  • Subtext skins are stored in the Skins folder. A sub folder in Skins points to a group of similar skins (called skin templates) not to a single skin.
  • Subtext uses the Skins.config file in the Admin folder in order to get the list of skins from which you can then select in your blog's control panel.

To create your own skin and learn the details of Subtext skinning I highly recommend to not start with any other skin than the "Naked" one, which comes with Subtext. The "Naked" skin essentially is a skin which is not styled in any way but implements most of Subtext's features. It also comes with an almost empty style sheet which you will customize heavily to give your blog an individual look and feel. By the way: While other blogging engines might require massive changes and rearrangement of (PHP) code, lots of things in Subtext can be done purely by using CSS. For almost all parts of the content Subtext provides CSS class or ID wrappers, so before you might want to touch ASP.NET code, double-check whether what you want cannot be achieved via CSS!

Creating a new skin

Start implementing your own skin by creating a new folder in the Skins folder and giving it a unique name. For this blog I have named the folder 24100. Copy the entire contents from Skins/Naked into the newly created folder. After this step your folders should look similar to this:

image

In the next step open the Skins.config file from the Admin folder. Anywhere within the <Skins> element add the following XML:

<Skins>
<SkinTemplate Name="24100.net" TemplateFolder="24100">
 <Styles>
 <Style href="~/skins/_System/commonstyle.css" />
 <Style href="~/skins/_System/commonlayout.css" />
 <Style href="style.css" />
 </Styles>
</SkinTemplate>

I simply copied the XML from the definition of the Naked skin within Skins.config and just changed the name and TemplateFolder attributes of the SkinTemplate element. Note: It is not important where in Skins.config you put the definition of your new skin as long as it is a direct child of the <Skins> element. Subtext's control panel lists the skins in order of their appearance inside Skins.config so I added mine to the top.

The above XML snippet tells Subtext that the files for your new skin with the name 24100.net reside in the Skins/24100 folder. In addition when Subtext renders this skin, it'll automatically generate <link> tags including two system CSS files (commonstyle.css and commonlayout.css) and the style.css which is inside the Skins/24100 folder. The style.css is where you will apply most of the modifications.

In the Configure section of the Subtext control panel Options menu activate your newly created skin:

image

Navigate to your blog. What you will see is an almost completely "unstyled" version of your blog. This is why the skin from which we created the copy is named Naked, I guess.

 

Understanding the base structure

The Web.config file

Before we move along let's dive a bit into the structure of a Subtext skin. Understanding the "execution chain" during rendering will later help us to quickly find components which we have to touch to achieve a specific look.

IIS and ASP.NET handle requests quite differently from the Apache and PHP stack. One thing to understand is that the URL's which get requested can be mapped to pages and handlers in arbitrary folders via the Web.config file in Subtext's root folder. I recommend to take a closer look at Web.config, more specifically to the <HandlerConfiguration> section.

One of the problems I faced was that at the time of this writing there was no complete overview as to which "part" of Subtext renders what. For example, to me it was not intuitively clear what gets rendered if a visitor selects the "Archives" link. The handler configuration inside Web.config is a good place to look for answers. To stick with the "Archives" example, in Web.config you find the following line:

<HttpHandler pattern="(?:/archives\.aspx)$" controls="SingleColumn.ascx"/>
 
Without getting into the details of ASP.NET handler configuration what this line does is, it instructs ASP.NET to use the SingleColumn.ascx control whenever a page with the .aspx extension in a archives folder is requested. SingleColumn.ascx is an ASP.NET user control. User controls are reusable components which can be embedded as a custom tag into an ASP.NET page in order to render parts of a page. A brief but clear introduction can be found here. (By the way: The SingleColumn.ascx user control sits within the Controls folder of your skin. Do not open it at this point as it is a pretty disappointing user control which just embeds yet another user control.)
 
Note: Should your Web.config file not contain the above HttpHandler configuration, chances are you did not open the Web.config file in the root folder of your Subtext installation. In fact ASP.NET allows Web.config files in every folder of an ASP.NET application and Subtext has various Web.config files in sub folders. Make sure you take the one in Subtext's root for the overall HttpHandler configuration lookup!

The PageTemplate.ascx user control

At the heart of every skin is the PageTemplate user control. Open the PageTemplate.ascx file in your skins root folder (Skins/24100). At the beginning of the user control you'll find a couple of Register directives. These directives instruct ASP.NET to recognize custom tags within the following markup and also configures which user controls will be used to generate the output which gets rendered where the custom tag is placed.

If you've followed these instructions you'll see that the following 10 user controls get registered:

<%@ Register TagPrefix="DT" Namespace="Subtext.Web.UI.WebControls" Assembly="Subtext.Web" %> 
<%@ Register TagPrefix="uc1" TagName="Header" Src="Controls/Header.ascx" %>
<%@ Register TagPrefix="uc1" TagName="Footer" Src="Controls/Footer.ascx" %>
<%@ Register TagPrefix="uc1" TagName="News" Src="Controls/News.ascx" %>
<%@ Register TagPrefix="uc1" TagName="SingleColumn" Src="Controls/SingleColumn.ascx" %>
<%@ Register TagPrefix="uc1" TagName="BlogStats" Src="Controls/BlogStats.ascx" %>
<%@ Register TagPrefix="uc1" TagName="MyLinks" Src="Controls/MyLinks.ascx" %>
<%@ Register TagPrefix="uc1" TagName="RecentComments" Src="Controls/RecentComments.ascx" %>
<%@ Register TagPrefix="uc1" TagName="RecentPosts" Src="Controls/RecentPosts.ascx" %>
<%@ Register TagPrefix="uc1" TagName="TagCloud" Src="Controls/TagCloud.ascx" %>
<%@ Register TagPrefix="uc1" TagName="SubtextSearch" Src="Controls/SubtextSearch.ascx" %>
 
So, for example whenever the following tag is rendered
 
<uc1:header id="Header1" runat="server" />

the Header.ascx control in Skins/24100/Controls will be executed.

If you open Skins/24100/Controls/Header.ascx you'll find the following markup:

<%@ Control Language="C#" EnableTheming="false" Inherits="Subtext.Web.UI.Controls.Header" %>
<%@ Register TagPrefix="uc1" TagName="SubtextSearch" Src="SubtextSearch.ascx" %>
 
<div class="title">
 <asp:HyperLink id="HeaderTitle" runat="server" />
</div>
<div class="subtitle">
 <asp:Literal id="HeaderSubTitle" runat="server" />
</div>
<uc1:SubtextSearch id="search" runat="server" />

So effectively the <uc1:header> custom tag will end up being rendered into three HTML <div> tags and yet another user control, the SubtextSearch.ascx.

You might think this is way overcomplicated but you will quickly recognize the beauty of this approach. It promotes reusability and a breaks your design into discrete components which drive maintainability of your code!

The main Cascading Style Sheet

The next thing you would like to inspect is the style.css file in your skins root directory. If you started based on the "Naked" skin it'll contain lots of empty selectors and a float:right directive for the #navigation ID selector.

You don't need to go through all the styles at this moment, just keep in mind that most of the customization can be achieved by defining CSS rules within this file. With that said, let's start customizing our skin!

Let the customizing begin

In case you're reading this post from my blog you see that my skin displays an image at the very top, sometimes called a header image:

image

I recommend to you to follow the next steps carefully. In fact I used this method over and over again with existing Subtext driven blogs in order to understand the structure of a Subtext blog better. I can not emphasize enough how much you learn from investigating what others have done before you!

1. Open my blog in Firefox and activate Firebug via Tools > Firebug > Open Firebug.

2. Select the Inspect button on Firebugs toolbar:

image

Once you've activated the Inspect mode Firebug allows you to mouse over the current web page and while you do so it puts a blue frame around distinct elements of the DOM tree. At the same time it highlights the underlying HTML code which created a specific DOM element. If you navigate to my blog's header image Firebug reveals that it is rendered via the <div> tag with the element ID "header":

image

So how did I achieve this? And what happened to the SubtextSearch user control which we saw in the Header.ascx a moment ago?

Well, it turns out that I customized the skin to create this effect. Let's review step by step:

First I opened Skins/24100/Controls/Header.ascx knowing that this user control will render the header of any of my blog's pages. (Please note: By writing "header" I do not refer to the <head> part of the HTML markup. There currently is no easy way to change the way this part gets rendered in Subtext.)

I deleted everything from Header.ascx except the first line. So the final version of my Header.ascx looks like this:

<%@ Control Language="C#" EnableTheming="false" Inherits="Subtext.Web.UI.Controls.Header" %>

Recall that in PageTemplate.ascx the header user control is rendered in between <div> tags with the "header" ID:

<div id="header">
 <uc1:header id="Header1" runat="server" />
</div>

With Header.ascx no longer outputting anything the final markup will only contain a <div id="header"> HTML tag. (Subtext is smart enough to omit a second closing </div> statement and generate the short form automatically.)

The final step to show my header image is to define the CSS rules in style.css for the header ID:

#header
{
 background-image:url(Images/header.jpg);
 height: 94px;
 border: 5px solid #fff;
}

With this done, all my pages will now show header.jpg at the very top.

Note: If you take a closer look at PageTemplate.ascx you'll notice that the entire content is wrapped by a <div> tag with the "container" ID. The next thing you would like to do is set some general CSS rules for this tag. For example in my skin the #container rules are as follows:

#container
{
 text-align: left;
 width: 934px;
 background-color: #fff;
 margin-top: 0px;
 margin-right: auto;
 margin-bottom: 0px;
 margin-left: auto;
 border: 1px solid #000;
}

The most important ones are defining the overall width of everything inside the container as being 934px and by setting margin-right and margin-left to auto centering the container on the page. My header.jpg image is 934px wide so everything aligns nicely.

At this point I'd like to encourage you to investigate the <div id="navigation"> section by yourself. Note how the

<uc1:mylinks id="MyLinks1" runat="server" />
<uc1:blogstats id="BlogStats1" runat="server" />
<uc1:news id="News1" runat="server" />
<uc1:RecentComments id="RecentComments1" runat="server" />
<uc1:RecentPosts id="RecentPosts1" runat="server" />
<uc1:singlecolumn id="SingleColumn1" runat="server" />
<uc1:TagCloud ID="tagCloud" runat="server" ItemCount="20" />

custom tags in PageTemplate.ascx correspond to the actual .ascx files in Skins/24100/Controls as registered at the beginning of PageTemplate.ascx. Feel free to open the corresponding .ascx controls and compare to what Firebug shows you until you get a pretty good feeling of what gets rendered and why.

This is it for the first part of this post. I am planning to write the second part Thursday evening, so stay tuned for more on Subtext skinning. In the next part we will focus on the <dt:contentregion id="MPMain" runat="server" /> section of PageTemplate.ascx, further style the skin and explain some more complex concepts of Subtext.

Any feedback is very welcomed!

 

tags: , , ,
comments
Mike stated:
# re: Skinning Subtext (Part 1)
Great intro! I'm switching to Subtext as well - and am looking forward to creating a custom Skin as well. I can't wait until your next post.
posted on 9/16/2007 5:26 AM
Akas h stated:
# re: Skinning Subtext (Part 1)
Hey...
I'm not a coder so I couldn't get most of this, but from what I gather it seems to be very comprehensive. Though, I cant seem to figure out how do I switch from the plain vanilla skin to another out of the box skin.
I haven't a clue.

Any suggestions..

Thanks!
posted on 11/26/2007 5:44 PM
# re: Skinning Subtext (Part 1)
I'm not a coder so I couldn't get most of this, but from what I gather it seems to be very comprehensive. Though, I cant seem to figure out how do I switch from the plain vanilla skin to another out of the box skin.
I haven't a clue.

Any suggestions..

Thanks!
posted on 7/2/2008 9:12 PM
post your comment
Title *
Name *
Email
Url
Comment *  
Please add 2 and 8 and type the answer here: