You have two methods for creating your skin. The method you choose depends on your comfort level with the technology and your personal preference. You can create skins using HTML, or if you prefer, you can create *.ascx skins with VS.NET. This enables you to develop your skin in a comfortable environment and provides flexibility while creating skins. If you are more of a designer who has developed traditional web sites in the past, you may prefer creating your skins in HTML using your favorite editor, but if you are more of a programmer, you may prefer using ASP.NET code and developing your skin with Visual Studio. Both of these methods are basically the same except you use tokens when developing in HTML and you use the user controls when creating your skin. Of course, the file extension will change depending on your choice of methods.
At a minimum, you want to develop two skins for each package: one to display to your users and another to display the administrative modules discussed in Chapters 4 and 5. The reason for this is that the user content areas probably need multiple panes to properly lay out the content as your business needs require, but the administrative areas are likely to display only a single module per page, so these two layouts will need to be architected differently to adequately serve the purpose of the area.
There are several steps to creating a skin. The order in which you perform these steps is not important, but the following is a valid method to get everything accomplished and your skin into production.
To simplify the development of skin files as well as expedite the packaging process later, it is recommended that you use the following organizational folder structure:
\Skins \SkinName (this is the package you are developing) ... (this is where you create the skin package zip files for deployment) \containers (this is a static name to identify the container files for the skin package) ... (this will contain all resource files related to your containers) \skins (this is a static name to identify the skin files for the skin package) ... (this will contain all resource files related to your skins)
This provides an easy structure to develop your skins — a structure that also simplifies preparing your package for deployment and installation into your portal. The free-form nature of skinning provides you a level of creative freedom within designing your skins. Designers may want to create the initial site designs as full graphical images and then slice the images to meet their needs after the concept is mature. One thing to be aware of when creating skins is that you need to include all user interface elements in your design — static elements such as graphics and text, active elements such as Login links, a navigation/menu system, and the other skin objects required for DotNetNuke to adequately display your content to your users.
This is where you need to be aware of the technical issues that will arise in terms of how to most effectively divide the graphical elements into the HTML representation you need. HTML layout is different from free-flow graphics, and the translation from a graphical image to an HTML representation determines the layout of the final design. Decisions such as what resolution you want to target for your site need to be made at this stage. If you want the site to remain fixed regardless of resolution of the user's browser or if the design should adapt to the resolution, you should make adjustments to your design accordingly. The download includes several example skins that display the differences between fixed-width skins and full-width skins, so you can see the differences between the two approaches.
Now that you have your design completed, you will need to actually build the skin. As mentioned earlier, you can use any HTML editor, Visual Studio, or if you prefer, even your favorite text editor to build the skin for your design. The one thing to remember is the HTML in your skin must be well formed or the process will fail. This means you must ensure you close any HTML tags you open, including image tags. Image tags do not normally have closing tags so you should include the trailing / after the image content and before you end the tag. Most modern HTML editors will handle the process of ensuring tags are closed for you, but you should still double-check your work to make sure a bug is not introduced into your skin with a missing tag.
Normally you want to include your images and support files within the same folder as the rest of your skin elements, but that isn't a requirement. You can place them in any folder you want, but care must be taken to ensure the paths will remain valid after the skin upload process. As part of the upload process the skinning engine adds <%= SkinPath %> to the beginning of your image paths for you. This allows your skin to be portable across installs and also to display properly when using the friendly URL feature of the framework. This variable will be populated at runtime with a relative value similar to /Portals/PortalId/Skins/YourSkinName/.
Before this inline variable was added to all the image paths during the skin upload, if someone was developing a site on his local machine in a virtual directory of http://localhost/VirtualDirectory and then decided to move it to production at a location of http://www.YourDomain.com, the skin would not render images properly. This left you with two options: you could install the skin again, effectively overwriting the original skin, or you could choose to directly edit the skin file and correct the image paths manually. Although the rendering of this variable does add overhead to the HTML output processing, it provides portability across installs.
If you would like to sacrifice portability in favor of performance, you can manually trigger the parsing process. To do this, select either Admin ð Skins or Host ð Skins. This opens the skin administration section where you will see a drop-down list with all the skins available to you based on your permissions. Choose the skin you want to alter from this drop-down list. If you have any skin preview images available (discussed later in the chapter), they are shown here. To complete the process, select the Localized option instead of Portable from the Parse Options radio button list and click the Parse Skin Package button. This parses your skin package the same as it does during the skin uploading process with the exception of how the image paths are altered.
Figure 16-1 shows the parsing options available to the administrator after a skin is installed.
Figure 16-1
The Skins page also has an About link, with its name based on the skin package name. The link displays an HTML file that provides details about the company and skin package for the administrator. This file, created by the skin designer, must be named About.htm or About.html and should be contained within the skins.zip file. Although the file is not necessary to create a functional skin, it is a nice addition to a skin package.
Now that you have your design and a good idea of how your skin will be architected, you need to add the skin objects to the proper location in your skin file. This is so DotNetNuke will know where to insert the various content panes, portal elements, and navigation objects. This process will change to meet the method you choose to create your skin. If you are using ASCX skins, you need to specify the @Register and the actual user control tag in your skin. For example, <dnn:Login runat=" server" > inserts the Login user control in the section of your skin where you specify the control. If you are using HTML skins, you simply need to include the token for the accompanying skin element. So for HTML skins, you just add [Login] in the location you want the Login control to appear, and the engine will replace it with the actual control when the skin is parsed during upload. Each of the skin objects has its own unique functions, and you must understand the use of each to build a functional skin. Table 16-1 lists each of these DotNetNuke core skin objects by token and control examples, and describes their purpose.
Token | Control | Description |
---|---|---|
[SOLPARTMENU] | < dnn:SolPartMenu runat="server" > | Displays the hierarchical navigation menu (formerly [MENU]).[SOLPARTMENU] skin object |
[LOGIN] | < dnn:Login runat="server" > | Dual state control — displays "Login" for anonymous users and "Logout" for authenticated users. |
[BANNER] | < dnn:Banner runat="server" > | Displays a random banner ad. |
[BREADCRUMB] | < dnn:Breadcrumb runat=" server" > | Displays the path to the currently selected tab in the form of Page-Name1 > PageName2 > Page-Name3. |
[COPYRIGHT] | < dnn:Copyright runat="server" > | Displays the copyright notice for the portal. |
[CURRENTDATE] | < dnn:CurrentDate runat="server" > | Displays the current date. |
[DOTNETNUKE] | < dnn:DotNetNuke runat="server" > | Displays the copyright notice for DotNetNuke (not required). |
[HELP] | < dnn:Help runat="server" > | Displays a link for help, which will launch the user's e-mail client and send mail to the portal administrator. |
[HOSTNAME] | < dnn:HostName runat="server" > | Displays the host title linked to the host URL. |
[LINKS] | < dnn:Links runat="server" > | Displays a flat menu of links related to the current tab level and parent node. This is useful for search engine spiders and robots. |
[LOGO] | < dnn:Logo runat="server" > | Displays the portal logo. |
[PRIVACY] | < dnn:Privacy runat="server" > | Displays a link to the privacy information for the portal. |
[SIGNIN] | < dnn:Signin runat="server" > | Displays the sign-in control for providing your username and password. |
[TERMS] | < dnn:Terms runat="server" > | Displays a link to the terms and conditions for the portal. |
[USER] | < dnn:User runat="server" > | Dual state control — displays a "Register" link for anonymous users or the user's name for authenticated users. |
[CONTENTPANE] | <div runat="server" id= "ContentPane"> | Injects a placeholder for module content. |
[LANGUAGE] | <dnn:LANGUAGE runat="server" /> | Displays a language selector drop-down list if the DotNetNuke install has more than one available option. |
[SEARCH] | < dnn:Search runat="server" > | Displays the search input box |
[TREEVIEWMENU] | < dnn:TreeViewMenu runat="server" > | Displays a navigation menu using the DNN treeview control to provide a Windows Explorer-like menu. |
These are the skin objects available for use in your skin creation, and some additional objects are available for use in the creation of containers. You can place these objects anywhere in your skin and control the placement of the portal elements. Not all these elements are required, but you should choose the elements you need to accomplish your purpose.
Important | Each skin must have at least one content pane, and it must be identified as the Content Pane or the modules will not display correctly. |
If you are able to log in to a DotNetNuke installation as a SuperUser, you can view these and any additional skin objects available to you. To view them, navigate to the Host's Module Definitions menu item. Usually, the first item listed is the [Skin Objects] module name. Click the edit pencil next to it, and a page opens with all the skin objects installed on that DotNetNuke install.
Quite a few attributes are also available for use in the skin creation process. The attributes are defined in skin.xml, the manifest file, mentioned earlier in the chapter. This file is where you tell DotNetNuke how you want to use the various skin objects. For example, if you want your navigation menu to display horizontally in your skin, set that in the skin.xml file so the engine will know how to properly insert the menu into the skin. Table 16-2 lists the attributes available for use in the manifest file for the skin objects.
Token | Attribute | Default | Description |
---|---|---|---|
[SOLPARTMENU] | separatecss | True | Determines whether the CSS defined in a style sheet is used (values: true, false). |
backcolor | #333333 | Background color. | |
forecolor | white | Forecolor of menu item when selected. | |
highlightcolor | white | Color of top and left border to give a highlight effect. | |
iconbackground color | #333333 | Background color in area where icon is displayed. | |
selectedborder color | Color of border surrounding selected menu item. | ||
selectedcolor | #CCCCCC | Background color of menu item when selected. | |
selectedfore color | white | Forecolor of menu item when selected. | |
display | horizontal | Determines how the menu is displayed (values: vertical, horizontal). | |
menubarheight | 16 | Menu bar height in pixels. | |
menuborderwidth | 1 | Menu border width in pixels. | |
menuitemheight | 21 | Menu item height in pixels. | |
forcedownlevel | false | Flag to force the downlevel menu to display (values: true, false). | |
moveable | false | Flag to determine if menu can be moved (values: true, false). | |
iconwidth | 0 | Width of icon column in pixels. | |
menueffects shadowcolor | dimgray | Color of the shadow. | |
menueffects mouseouthide delay | 500 | Number of milliseconds to wait until menu is hidden on mouse out (0 = disable). | |
menueffects mouseover display | Highlight | Adjusts the effect when mouse moves over a menu bar item (values: Outset, Highlight, None) | |
menueffects mouseover expand | true | Makes the menu expand on mouse-over, unlike any menu found within the Windows environment (values: true, false). | |
menueffects style | filter: progid:DX Image Transform .Microsoft .Shadow(color= 'DimGray', Direction=135, Strength=3) ; | IE-only property for submenu styles and transitions. | |
fontnames | Arial | Name of the font used by the menu. | |
fontsize | 12 | Size of the font used by the menu. | |
fontbold | false | Determines whether the font used by the menu is bold (values: true, false). | |
menueffects shadowstrength | 3 | Determines how many pixels the shadow extends. | |
menueffects menutransition | None | Determines which direction the shadow will fall (values: None, AlphaFade, AlphaFadeBottom-Right, Barn, Blinds, Checker-board, ConstantWave, Fade, GradientWipe, Inset, Iris, RadialWipe, Random, Random-Bars, Slide, Spiral, Stretch, Strips, Wave, Wheel, Zigzag). | |
menueffects menutransition length | 0.3 | Number of seconds the transition will take. | |
menueffects shadowdirection | Lower Right | Determines which direction the shadow will fall (values: None, Top, Upper Right, Right, Lower Right, Bottom, Lower Left, Left, Upper Left). | |
menucontainer cssclass | MainMenu_ MenuContainer | Menu container CSS class. | |
menubarcssclass | MainMenu_ MenuBar | Menu bar CSS class. | |
menuitemcssclass | MainMenu_ MenuItem | Menu item CSS class. | |
menuiconcssclass | MainMenu_ MenuIcon | Menu icon CSS class. | |
menuitemselcss class | MainMenu_ MenuItemSel | Menu item CSS class for mouse-over. | |
menubreakcss class | MainMenu_ MenuBreak | Menu break CSS Class. | |
submenucssclass | MainMenu_ SubMenu | Submenu CSS class. | |
menuarrowcss class | MainMenu_ MenuArrow | Menu arrow CSS class. | |
menuroot arrowcssclass | MainMenu_ MenuRootArrow | Menu root arrow CSS class. | |
forcefull menulist | false | Displays the full menu as an indented list of normal hyperlinks, much like a sitemap (values: true, false). | |
useskinpath arrowimages | false | Determines whether arrow images located in the skin are used and not those in the /images folder (values: true, false). | |
userootbread crumbarrow | true | Determines whether a bread crumb arrow is used to identify the root tab that is listed in the breadcrumb ArrayList (values: true, false). | |
usesubmenu breadcrumbarrow | false | Determines whether a bread crumb arrow is used to identify the submenu tabs that are listed in the breadcrumb ArrayList (values: true, false). | |
rootbreadcrumb arrow | Image used for root-level menu breadcrumb arrows; for example, file.gif. | ||
submenubread crumbarrow | Image used for submenu menu breadcrumb arrows; for example, file.gif. | ||
usearrows | Uses arrows to indicate child sub-menus. | ||
downarrow | menu_down .gif | Arrow image used for downward-facing arrows indicating child sub-menus. | |
rightarrow | breadcrumb .gif | Arrow image used for right-facing arrows indicating child submenus. | |
level | Root | Root level of the menu in relation-ship to the current active tab (values: Root, Same, Child). | |
rootonly | false | Indicator to turn off submenus (values: true, false). | |
rootmenuitem breadcrumbcss class | CSS class used for root menu items when they are found in the breadcrumb ArrayList. | ||
submenuitem breadcrumbcss class | CSS class used for submenu items when they are found in the bread crumb ArrayList. | ||
rootmenuitemcss class | CSS class used for root menu items. | ||
rootmenuitem activecssclass | CSS class used for root menu items when they are the active tab. | ||
submenuitem activecssclass | CSS class used for submenu items when they are the active tab. | ||
rootmenuitem selectedcss class | CSS class used for root menu items when they are moused over. | ||
submenuitem selectedcss class | CSS class used for submenu items when they are moused over. | ||
separator | The separator between root-level menu items. This can include custom skin images, text, and HTML (for example, <![CDATA[ <img src="/books/3/435/1/html/2/file.gif"> ]]>). | ||
separatorcss class | CSS class used for the root-level menu item separator. | ||
rootmenuitem lefthtml | HTML text added to the beginning of the root menu items. | ||
rootmenuitem righthtml | HTML text added to the end of the root menu items. | ||
submenuitem lefthtml | HTML text added to the beginning of the submenu items. | ||
submenuitem righthtml | HTML text added to the end of the submenu items. | ||
tooltip | Tooltips added to the menu items. These come from the tab object properties, which are filled from the tabs table (values: Name, Title, Description). | ||
leftseparator | The separator used just before a root-level menu item, such as a left edge of a tab image. | ||
rightseparator | The separator used just after a root-level menu item, such as a right edge of a tab image. | ||
leftseparator active | The separator used just before an active root-level menu item. | ||
rightseparator active | The separator used just after an active root-level menu item. | ||
leftseparator breadcrumb | The separator used just before a root-level menu item found in the breadcrumb ArrayList. | ||
rightseparator breadcrumb | The separator used just after a root-level menu item found in the breadcrumb ArrayList. | ||
leftseparator cssclass | CSS class used for the left separator. | ||
rightseparator cssclass | CSS class used for the right separator. | ||
leftseparator activecssclass | CSS class used for the left separator active | ||
rightseparator activecssclass | CSS class used for the right separator active. | ||
leftseparator breadcrumbcss class | CSS class used for the left separator breadcrumb. | ||
rightseparator breadcrumbcss class | CSS class used for the right separator breadcrumb. | ||
menualignment | Left | Alignment of the menu within the menu bar (values: Left, Center, Right, Justify). | |
cleardefaults | false | If true, this value clears (empties) the default color settings of the menu so that they can be left empty and not just overridden with another value | |
delaysubmenuload | false | If true, this setting delays the loading of the menu until the rest of the page has rendered. | |
[LOGIN] | Text | Login | Text of the login link. |
CssClass | OtherTabs | Style of the login link. | |
LogoffText | Logoff | Text for the logoff link | |
[BANNER] | BorderWidth | 0 | Border width around the banner. |
[BREADCRUMB] | Separator | breadcrumb .gif | The separator between bread crumb links. This can include custom skin images, text, and HTML (for example, <![CDATA[ <img src="/books/3/435/1/html/2/ file.gif" > ]]>). |
CssClass | SelectedTab | Style name of the breadcrumb links. | |
RootLevel | 1 | The root level of the breadcrumb links. Valid values include:
| |
[COPYRIGHT] | CssClass | SelectedTab | Style name of portal copyright link. |
[CURRENTDATE] | CssClass | SelectedTab | Style name of date text. |
DateFormat | MMMM dd, yyyy | Format of the date text. | |
[DOTNETNUKE] | CssClass | Normal | Style name of DotNetNuke portal engine copyright text. |
[HELP] | CssClass | OtherTabs | Style name of help link. |
[HOSTNAME] | CssClass | OtherTabs | Style name of Host link (powered by xxxxxxxxx). |
Separator | | The separator between links. This can include custom skin images, text, and HTML (for example, <![CDATA[ <img src="/books/3/435/1/html/2/ file.gif"> ]]>). | |
Alignment | Horizontal | Links menu style (values: Horizontal, Vertical). | |
Level | Same | Determines the menu level to display (values: Same, Child, Parent, Root). | |
[LOGO] | BorderWidth | 0 | Border width around the logo. |
[PRIVACY] | Text | Privacy Statement | Text of the privacy link. |
CssClass | OtherTabs | Style name of privacy link. | |
[SIGNIN] | The entire login control (not just a link to a page that contains the login control) will be placed within the skin where this token is used. This is legacy and not recommended for use. | ||
[TERMS] | Text | Terms of User | Text of the terms link. |
CssClass | OtherTabs | Style name of terms link. | |
[USER] | Text | Register | Text of the register/user link. |
CssClass | OtherTabs | Style name of register/user link. | |
[CONTENTPANE] | ID | ContentPane | Content pane key identifier to be displayed in the user interface and stored in the database. |
[LANGUAGE] | CssClass | Style name of the drop-down list. | |
[SEARCH] | Submit | Submit | HTML to activate the search lookup (for example, "Search" or "Go" or <img src="/books/3/435/1/html/2/ mybutton.gif">). |
CssClass | CSS class for the search control. | ||
[TREEVIEWMENU] | BodyCssClass | CSS class for the body of the tree-view menu. | |
CssClass | CSS class for the treeview control. | ||
HeaderCssClass | CSS class for the header. | ||
HeaderTextCss Class | Head | CSS class for the header text. | |
HeaderText | Text for the header of the tree menu. | ||
IncludeHeader | True | ||
Level | Indicates the root level of the tree menu (blank = root). | ||
NodeChildCss | Normal | CSS class for a child node. | |
Class | |||
NodeClosedImage | folderclosed .gif | Image for a closed (not in current breadcrumbs but has children) node. | |
NodeCollapse Image | min.gif | Image to show that will activate a collapse of the menu node. | |
NodeCssClass | Normal | CSS class for the nodes. | |
NodeExpandImage | max.gif | Image to show that will activate an expansion of the menu node. | |
NodeLeafImage | file.gif | Image used for a "leaf" node (no children). | |
NodeOpenImage | folderopen .gif | Image for an opened (in current breadcrumbs and has children) node. | |
NodeOverCssClass | Normal | CSS class for a node on mouse over. | |
NodeSelected CssClass | Normal | CSS class for the selected node. | |
NoWrap | false | Replaces spaces in the text of the node with nonbreaking spaces. | |
ResourceKey | Resource key to localize the Title text. If blank, Text property will be used. | ||
RootOnly | false | Show only the root menu (no children). | |
TreeCssClass | CSS class for the tree. | ||
TreeGoUpImage | folderup.gif | Image to go up a level on the tree. | |
TreeIndentWidth | 10 | Additional width to indent each tree level. | |
Width | 100% | Width of the tree control. |
As you can see, there are quite a few attributes for each skin object. This complicates the process of creating skins a bit, but it is important that you learn to use the attribute functions of each skin object to adequately realize the true power and flexibility of the DotNetNuke skinning engine. You may notice that the menu control monopolizes the majority of the available attributes — this shows the flexibility of the menu system DotNetNuke uses. One thing to note here is that the menu control is a fluid development control, which means it is constantly receiving revision and this list of attributes may not be complete by the time you are reading this book. Take a look at the menu documents available for download to ensure you are aware of all the options available to you with this powerful control.
The skinning engine will support multiple instances of the skin objects where you can define multiple menus for your skin or any other instance. You must of course give each instance an unique name, so you could have a menu skin object defined as [MENU] and a second menu defined as [MENU:1]. The value of 1 was used as the example name here but any descriptive name can be used here such as [MENU:Top]. These are also important for your content areas because it is likely you will want more than one content area for your skin. You must have at least one pane named [ContentPane], but you will likely want other areas to organize your content in so you can use the named instances like with the menu, only use the content skin object instead of the menu.
You can also set the attributes for each of your skin objects according to the ones previously listed in Table 16-2. Each skin object will support the attributes and you can specify them when you define the skin object. For example, in the earlier example of defining your Login control, you could have specified the text for your control such as <dnn:Login runat="server" Text="Signin" />. This example works only if you are creating ASCX skins. If you are working with HTML skins, you must include the attribute setting in the manifest file.
A skin package may contain global attributes specified in a file named skin.xml (or container.xml for containers) that will apply to your skin files. You can also override the global skin attribute specification with a skin-specific attribute specification by providing a YourSkinFile.xml file. The Skin Uploader will merge the skin attributes with the HTML presentation file to create an ASCX skin file. Listing 16-4 shows a section of the manifest file where these attributes are set.
Listing 16-4: Skin Attribute Example
<Objects> <Object> <Token>[LOGIN]</Token> <Settings> <Setting> <Name>Text</Name> <Value>Signin</Value> </Setting> </Settings> </Object> </Objects>
As you can see, the code in Listing 16-4 accomplishes the same thing as in the ASCX example, but you are able to keep the additional attributes separate from the presentation. This allows for cleaner and easier-to-understand HTML as you create HTML skins because the attributes do not congest the code with additional overhead.
There is a one-to-one relationship of skin object definitions in the skin file (that is, [MENU]) with the attribute specification in the skin.xml file. This is also true for all named instances. For example, if you want to include a vertical and horizontal menu in your skin, you can specify [MENU:1] and [MENU:2] named instances in your skin file and then create definitions for each with different attributes in the skin.xml file.
When creating HTML skins and specifying multiple ContentPanes, you need to stipulate the ID attribute in the attributes file. That enables DotNetNuke to identify the proper pane to insert your modules into while you are administering the portal. It also gives you the ability to add some friendly descriptive names to the various panes you may require. For example, Listing 16-5 shows how the ID of the pane is defined in the manifest file. You can define as many nodes of these various pane IDs as required to accomplish your design.
Listing 16-5: Content Pane Attributes
<Objects> <Object> <Token>[CONTENTPANE:1]</Token> <Settings> <Setting> <Name>ID</Name> <Value>RightPane</Value> </Setting> </Settings> </Object> </Objects>
The code creates a pane named RightPane that you can use to display content to the user. You could also define a LeftPane or NavigationPane — basically whatever your business rules require you to include in the skin. This shows some of the flexibility the solution provides because you are able to use the number of panes necessary to accomplish your design. The solution enables you to create a layout to use the application as necessary. By using a combination of the code within your skin and the attributes file, you can create almost any iteration of a skin design you can imagine.
The reason one content pane must be named ContentPane is for consistency across all installed skins. During the page rendering, modules are loaded into content panes based on the name of the pane the module is assigned to. Having this required pane name enables you to change from one skin to another, which may have content panes of completely different names or a layout with fewer content panes, and not cause an error to occur. This is because if the pane the module was assigned to is not found, it will simply be loaded in the commonly named ContentPane, which must exist in all installed skins.
Now that you understand the way skins are designed, you can look at building a Cascading Style Sheet (CSS) for your skin. The CSS file will need to be defined and saved in your skin directory along with your other resource files. DotNetNuke uses an external style sheet specification, which enables you to define your styles separate from your skin files, and there are several levels of these files. This means it is not essential for you to create a CSS file for your skin because one of the other files will define the styles for you. But to keep a unique look to your skin design, you will want to build a style sheet specific for your skin design. The multiple style sheets in the application are structured in a hierarchal nature, so one style sheet's definitions may override another. There is a distinct priority of the order in which overriding of styles can occur. The cascading order of the style sheets is summarized in the following list with the previous item overriding the next:
Modules: The modules style sheet determines the styles that can be used in the individual module.
Default: This is the default style sheet for the host-level styles and the styles are defined in default.css.
Skin: These are the skin styles you will create and apply to your skin.
Container: Each container can contain styles unique to its design.
Portal: These are custom styles defined by the Portal Administrator and named portal.css.
You can define your skin's style sheet in one of two ways. You can create a style sheet named skin.css and place it in your skin directory. That file will apply to all skins that may reside in the skin package. You can also name your style sheet with the format of skinname.css, and it will apply to the skin file with the same name as the one you define here. You can add any style definitions you need, but at the minimum, you should override the default styles with those that complement the design of your skin.
After you have the skin created, you need to create an image so you will be able to display the skin in the preview gallery. In order to do this, you need to create a high-quality image file with a .jpg extension that must be named the same as your skin file. For example, if your skin is named mySkin.ascx, then your image file must be named mySkin.jpg. At the time of upload, a thumbnail image will be generated for each properly named .jpg. This same concept is also true of container files you have created as part of your skin design. The skin preview images are displayed on the same page as the About.htm link discussed previously in this chapter and shown in Figure 16-1.
The last step in skin creation is to package the skin for deployment. The compressed file must be a *.zip file. You can use any number of third-party compression utilities, such as WinZip or Windows XP's built-in utility. One thing to watch out for when zipping your package is to ensure there are no buried folders between your skin files and the first-level compressed folder. This is a common mistake that causes the upload process to fail.
In many cases, you will want to package a complementary set of skin files and container files (which will be discussed shortly) in one distribution file. To do this, package your container files in a compressed *.zip file named containers.zip. Similarly, package your skin files in a compressed *.zip file named skins.zip, which was mentioned at the beginning of this chapter. Then, package these two files into a single *.zip file that is named after your skin. This allows people to install the full skin package (skins and containers) by uploading a single file through the Skin Uploader.