- Built on EPiServer CMS 7
- Templates built on ASP.NET 4.0 using Web Forms
- Based on the responsive Bootstrap by Twitter HTML framework
- Uses config transforms for configuration management
An introduction to Bootstrap
The Alloy site markup is based on the responsive HTML framework Bootstrap.
The basic idea is to make it easier to go from this…
…to this, depending on the size of the browser:
Basic building blocks in Bootstrap
Bootstrap is based on rows, each consisting of one or more content elements that span a certain relative width.
The HTML looks something like this:
The first row would normally render something like this…
…while rendering something like this when the browser window becomes small enough (think handheld devices):
Because of Bootstrap we want our content areas to be rendered as one or more rows which in turn contain blocks as content elements. To make things even more interesting, we want to “fill” each row with blocks to ensure a nice adaptive layout.
Basic layout concept
When a single block is added to a content area we want it to be rendered as a single row with a single full-width content element:
When we add a second block, we want it to fill the row together with the first block:
We want the same principle if we add a third block:
However, if we add a fourth block it will no longer fit in the same row. Therefore we want a new row containing the fourth block as a full width element (as there are no more blocks to share the row with):
Layout concept involving minimum and maximum block widths
The basic layout concept described earlier works because most of Alloy’s block controls support dynamic widths ranging from 1/3 to full width.
However, it’s not always practical to have a block control which can vary so freely in size.
To manage this, we introduced properties to define minimum and maximum widths for Alloy block controls.
This means we could potentially add seven different blocks which would be rendered like this:
Note that the last block is full width even though it’s minimum size is 4 (one third). That’s because it won’t fit in the previous row, and since there are no more blocks to render the last block can stretch out across the entire row.
The simplified Tetris theory
Whenever a content area is rendered, a block control is resolved for each block. We take all these block controls and play a game of simplified Tetris to arrange the blocks in neatly filled rows, according to the minimum and maximum widths of each block control.
Custom content area rendering
To support these design requirements for the Alloy website we use a custom control called SitePropertyContentAreaControl to render content areas.
This control inherits the native PropertyContentAreaControl, with some added Tetris-like aspects to support the type of layouts described earlier.
To make EPiServer use our own control to render all content area (i.e. all PropertyContentArea properties) we have added an initializable module like this:
This means we can render our content areas using the standard Property control while still getting our customized rendering of content areas:
This is done by a post-build event which triggers the YUI compressor. For details, check out the Scripts.xml and Stylesheets.xml files in the [MSBuild] folder.
Stylesheets are minified and/or concatenated into a non-minified file called combined.css and a minified equivalent called combined.min.css:
These files are linked in the Root.Master master page using simple web controls:
When the site is built in debug mode…
…the non-minified versions will be linked:
Otherwise the minified versions will be linked:
To deal with different configuration setups we use chained config transforms:
This means we have a set of default configuration files…
…which contain generic configuration settings valid for any EPiServer 7 website:
We then apply a set of common config transforms for our particular website…
…which contain modifications to the generic configuration settings…
…which results in a configuration file where some of the generic configuration elements have been updated:
Lastly, we apply a set of build-specific config transforms. The build-specific transforms are determined by the name of the build configuration. For example, if we select “Debug” as our build configuration…
…the build-specific transforms will be retrieved from a folder called /[Configuration]/Debug:
These transforms are applied after the common transforms…
…which results in a build-specific configuration, such as local development or production release…
…which is then copied to the site root:
Note: do not edit the configuration files in the site root as they will be overwritten on every build. Instead make your configuration changes in the common or build-specific config transforms. This also means that the root configuration files should not be included in source control.
The config transforms are triggered on each build through a post-build event:
1. My web.config changes keep disappearing. What gives?
Only edit configuration files under the [Configuration] folder, the root configuration files are overwritten on every build because of the config transforms.
2. Why is it built on Web Forms instead of MVC?
Although EPiServer 7 fully supports both Web Forms and MVC, Web Forms is still the more widely used. For that reason we decided to start with a Web Forms-based version.
Alloy is built on ASP.NET 4.0, bundling came with ASP.NET 4.5.
That’s because they’re not included in the project file (that’s a bug, sorry). They should be included in the project but not included in source control as they are overwritten with each build.
5. Why isn’t a CSS framework like LESS or SASS used?
To minimize package dependencies and avoid confusing developers not familiar with them. Both work just fine, though!
Known bugs, limitations and annoyances in Alloy
- The editmode.css file in /Static/css is obsolete, it can safely be removed if it’s also removed from the Stylesheets.xml MSBuild file (otherwise CSS concatenation will fail).
- The ClonedContentProvider’s cache does not depend on the original cloned pages.
Feedback, suggestions or questions?
Tweet me at @tednyberg, e-mail me at firstname.lastname@example.org, or just shout really, really loud.