
Темы и скины в ASP.NET Web Forms: оформление сайта без копипасты
Темы ASP.NET позволяют задать вид всех GridView, кнопок и полей ввода в одном месте и переключать оформление сайта целиком. Разбираем устройство тем, скины и смену темы на лету.
Какую задачу решают темы
На крупном сайте Web Forms десятки страниц с GridView, кнопками и полями ввода. Если цвет шапки таблицы или ширина поля прописаны в разметке каждого элемента, любое изменение оформления превращается в поиск и замену по всему проекту. Темы, появившиеся в ASP.NET 2.0, выносят эти свойства в отдельное место.
Тема состоит из двух видов файлов. Обычные CSS-файлы описывают стили HTML, как и на любом сайте. Файлы скинов (.skin) задают значения свойств серверных элементов управления: CssClass, BorderWidth, стили строк GridView, шаблон PagerSettings. Скин срабатывает на сервере до формирования HTML, поэтому настраивает то, до чего CSS не дотянется.
Структура папки App_Themes
Темы хранятся в специальной папке App_Themes в корне приложения. Каждая подпапка это отдельная тема, её имя и есть имя темы. Внутри лежат файлы .skin, .css и картинки, на которые ссылаются стили.
Все CSS-файлы темы подключаются к странице автоматически, в алфавитном порядке имён. Если порядок важен (сначала сброс стилей, потом основные), называйте файлы с числовым префиксом: 01-reset.css, 02-site.css. Для автоматического подключения нужен элемент head с атрибутом runat=«server».
App_Themes\
Blue\
01-reset.css
02-site.css
Controls.skin
GridView.skin
images\header.png
Dark\
01-reset.css
02-site.css
Controls.skin
GridView.skinСкин по умолчанию и именованные скины
Файл скина похож на разметку ASPX, только без ID. Элемент без атрибута SkinID становится скином по умолчанию: его свойства получат все элементы этого типа на страницах с темой. Элемент с SkinID это именованный скин, он применяется только к тем элементам, у которых указан такой же SkinID.
Для каждого типа элемента допустим один скин по умолчанию и сколько угодно именованных. Скины распределяют по нескольким файлам ради удобства, для ASP.NET все .skin в папке темы объединяются в один набор.
<%-- скин по умолчанию: все TextBox на сайте --%>
<asp:TextBox runat="server" CssClass="input" />
<%-- именованный скин: только кнопки с SkinID="Primary" --%>
<asp:Button runat="server" SkinID="Primary" CssClass="btn btn-primary" />
<asp:Button runat="server" CssClass="btn" />
<%-- единый вид всех таблиц --%>
<asp:GridView runat="server" CssClass="grid" GridLines="None"
AllowPaging="True" PageSize="20">
<HeaderStyle CssClass="grid-head" />
<AlternatingRowStyle CssClass="grid-alt" />
<PagerStyle CssClass="grid-pager" />
</asp:GridView>Theme и StyleSheetTheme: кто кого перекрывает
Тему подключают двумя атрибутами, и разница между ними принципиальна. Атрибут Theme применяется после свойств, заданных в разметке страницы, и перекрывает их: если в скине CssClass=«input», а у элемента на странице CssClass=«wide», победит скин. Атрибут StyleSheetTheme применяется до разметки, и свойства страницы его перекрывают, как обычный каскад CSS.
Для общего оформления сайта обычно удобнее StyleSheetTheme: он задаёт разумные значения по умолчанию, а отдельная страница может их уточнить. Theme подходит, когда оформление должно быть строго единым и разработчики страниц не должны его менять.
- на одной странице: атрибут Theme=«Blue» или StyleSheetTheme=«Blue» в директиве @Page;
- для всего сайта: элемент pages с атрибутом theme или styleSheetTheme в web.config;
- для отдельного элемента отключение: EnableTheming=«false».
Смена темы во время работы
Дать пользователю выбрать оформление (светлое, тёмное, контрастное) можно программно. Свойство Page.Theme разрешено устанавливать только в событии PreInit, позже ASP.NET уже применил скины, и попытка вызовет InvalidOperationException. Выбор пользователя хранят в cookie или профиле и читают в PreInit.
Чтобы не повторять код на каждой странице, его выносят в базовый класс, от которого наследуются все страницы сайта. Перед установкой проверяйте, что такая папка темы существует, иначе получите ошибку при запросе.
Public Class BasePage
Inherits System.Web.UI.Page
Private Shared ReadOnly Allowed As String() = {"Blue", "Dark", "Contrast"}
Protected Overrides Sub OnPreInit(e As EventArgs)
Dim cookie = Request.Cookies("theme")
If cookie IsNot Nothing AndAlso Array.IndexOf(Allowed, cookie.Value) >= 0 Then
Me.Theme = cookie.Value ' только здесь, в PreInit
End If
MyBase.OnPreInit(e)
End Sub
End ClassЛовушки при работе с темами
Темы удобны для оформления самих серверных элементов, но верстку сетки страницы, отступы и типографику по-прежнему держите в CSS. Хорошее разделение: скин задаёт только CssClass, а все визуальные значения живут в стилях темы.
- нет head runat=«server», и CSS-файлы темы молча не подключаются;
- CSS из темы выводится после ваших link в head, поэтому стили темы перекрывают стили, подключённые вручную;
- браузер кэширует CSS темы, после правки стилей добавьте версию в имя файла или очистите кэш;
- в Master Page атрибут Theme не задаётся, тема ставится у страницы или в web.config;
- скины применяются только к серверным элементам, обычный HTML-тег input скин не получит.
Как это делают сегодня
Вопросы и ответы
Почему стили темы не подключаются к странице?
Скорее всего, у head нет атрибута runat=«server». ASP.NET добавляет ссылки на CSS темы только в серверный head.
Чем Theme отличается от StyleSheetTheme?
Theme применяется после свойств страницы и перекрывает их, StyleSheetTheme применяется до них и уступает разметке. Для оформления по умолчанию удобнее StyleSheetTheme.
Где менять тему из кода?
Только в событии PreInit страницы или в OnPreInit базового класса. Позже установка свойства Theme вызывает исключение.