Share via


快速入门:定义应用布局 (HTML)

[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]

可以针对任何窗口大小或方向定义应用布局。

请将此操作功能视为我们的应用功能大全系列的一部分。: Windows 应用商店应用 UI 全解

目标: 在阅读本文之后,你将对如何使用 HTML、级联样式表 (CSS) 和 JavaScript 来创建在所有视图状态下外观良好且功能正常的流体 UI 具有扎实的理解。

先决条件

  • 对你的应用的设计要心中有数。

    你可以在定义构想中了解如何规划和设计 Windows 运行时应用。

  • 熟悉 Windows 8.1 中可调整大小的窗口。

    你可以在布局和缩放 UX 指南中了解关于视图状态的详细信息。

  • 了解 CSS 媒体查询。

    媒体查询是在万维网联盟 (W3C) 媒体查询规范中定义的。你可以在我们的 CSS 媒体查询示例中看到此操作中的媒体查询。

  • 了解如何使用级联样式表第 3 层 (CSS3) 高级布局功能,特别是 CSS3 网格对齐。

    你可以在 CSS 中了解 CSS3 高级布局功能和网格对齐。

使用 CSS 的自适应布局示例

本文通过描述如何在使用 CSS 的自适应布局示例中实现布局,阐述定义应用布局中所涉及的基本概念。此示例是一个模拟天气应用,它显示当日的天气和十天的天气预报。它演示了如何使用 CSS 和 HTML、CSS 网格、ListView 控件和 CSS 媒体查询来创建流体应用布局。

在我们进入细节之前,让我们看一下使用 CSS 的自适应布局示例的结构。该应用包括三个 HTML 页面。第一个是一个称为 App.html 的顶层页面,该页面定义应用的 UI 项的主要表面。它包含一个后退按钮、一个标题和子标题、一个应用菜单、几个应用栏按钮和一个用于显示内容的区域(下图中的白色区域)。

示例应用的主页面

其他两个 HTML 页面(Current.html 和 TenDay.html)定义在主页面的内容区域中显示的内容的结构。Current.html 页面显示关于当日天气的详细信息:

当日天气页面

TenDay.html 页面显示关于十天天气预报的详细信息:

十天天气预报页面

我们将重点介绍具有 CSS 的自适应布局示例的各个部分,该示例定义应用的主要页面布局以及十天天气预报页面的布局。

以下是在全屏纵向和横向以 1366 x 768 的分辨率在 10.6" 显示器上显示十天天气预报时以及与其他应用并排放置,将大小调整为窄布局和宽布局时应用主页面的外观。

纵向、横向、窄和宽布局

确保应用填充可用的屏幕区域

设计良好的应用的 UI 表面会占据所有可用屏幕区域。首先,考虑到应用需要适应的范围广泛的设备外形尺寸、分辨率和方向,这可能看起来就是一个很困难的挑战。幸运的是,CSS 使这一切变得非常容易。

要确保应用占据所有可用的屏幕区域,请执行以下操作:

  1. 将某个 div 元素用作页面上所有其他 UI 元素的顶层容器。

    <body>
        <div class="win-ui-dark appGrid">
            <!-- TODO: Define page structure here. -->
        </div>
    </body>
    
  2. 使用 CSS 属性(vwvh)来设置与视口相关的 divwidthheight 属性。例如,使用 100vw(视口宽度)和 100vh(视口高度)来填充视口,如下所示。

    .appGrid {
        width: 100vw;
        height: 100vh;
        /* TODO: Add other styles here. */
    }
    

    可以为任何元素指定 vwvh,无论该元素的层次结构有多深。因为视口的大小上下文不会更改,所以不需要考虑继承大小。

    注意  该示例将 widthheight 属性设置为 100%。

     

定义主页面的基本布局

设置你的应用 UI 的布局时,最好从横向开始。在定义你的横向布局之后,对于纵向和窄宽度布局,将很容易适应它。

使用 HTML 为页面定义 UI 项

应用 UI 通常会包含诸如导航按钮、标题、菜单、控件等项。将这些 UI 项添加为页面的顶层 div 元素的子 HTML 元素。

以下 HTML 定义使用 CSS 的自适应布局示例应用的顶层页面的 UI 项。这些项包括后退按钮、标题和子标题、应用菜单、主要内容区域和应用栏按钮。

<body>
    <div class="win-ui-dark appGrid">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back"></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="win-type-xx-large titlecontainer" tabindex="0"><span class="pagetitle">Mountains</span><span class="win-type-x-large chevron">&#xE099</span></span>
                <span class="win-type-x-large pagesubtitle">Rainer</span>
            </h1>
        </header>
        <div id="headerFlyout" data-win-control="WinJS.UI.Menu">
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'rainierMenuItem', label:'Rainier'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'stHelensMenuItem', label:'St. Helens'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'olympusMenuItem', label:'Olympus'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'bakerMenuItem', label:'Baker'}"></button>
            <button data-win-control="WinJS.UI.MenuCommand" data-win-options="{id:'adamsMenuItem', label:'Adams'}"></button>
        </div>
        <div class="appViewContentMask">
            <div class="appViewContent">
                <div id="current-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/current.html', data: FluidAppLayout.Data.mountains[0].weatherData[0]}"></div>
                <div id="ten-day-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/tenDay.html', data: FluidAppLayout.Data.mountains[0].weatherData}"></div>
            </div>
        </div>
    </div>
    <div id="appbar" class="win-ui-dark appbar" data-win-control="WinJS.UI.AppBar">
        <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id: 'current', label: 'Current', icon: 'calendarday', type: 'toggle', onclick: FluidAppLayout.transitionPivot, selected: 'false', tooltip: 'Get the current report'}"></button>
        <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id: 'tenDay', label: 'Ten day', icon: 'calendarweek', type: 'toggle', onclick: FluidAppLayout.transitionPivot, selected: 'false', tooltip: 'Get the ten day report'}"></button>
    </div>
</body>

使用 CSS 网格在 HTML 页面上定位 UI 项

实现流体和自适应 UI 布局的其中一种最佳方法是通过使用 CSS 网格。这是因为网格可以自动扩展以填充给予它的空间,并且它会公开一组丰富的属性,这使得为各种窗口大小定制 UI 布局都非常容易。因为网格中元素的位置与指定它们的顺序无关—即,它们的位置单纯由 CSS 指定,而不是由 HTML 标记中的顺序指定—所以很容易在不同屏幕大小上或在不同的方向为元素指定不同的排列方式,甚至可以完全避免在某些布局上显示某些元素。

设置主页面的布局

  1. 使用 CSS 的自适应布局示例应用通过设置 div -ms-griddisplay 属性,将 CSS 网格应用到 App.html 页面上的顶层 div。此顶层网格定义将 UI 项放置在应用的主页面上的整体结构。

  2. 接下来,该示例应用将通过设置 -ms-grid-columns-ms-grid-rows 属性的值定义网格的列数和行数。

    以下 CSS 代码将一个网格应用于示例的主页面上的顶层 div。 此网格用于定位构成应用的标题(后退按钮、标题和子标题以及应用菜单)的项,并用于设置主要内容区域的位置。

    .appGrid {
        display: -ms-grid;
        -ms-grid-columns: 120px 1fr;
        -ms-grid-rows: 120px 1fr; 
    
        /* Other properties omitted for clarity. */
    
    }
    

    上述 CSS 代码创建了一个包含两列和两行的网格。第一列为 120 像素宽,而第二列为一个“分数单位”宽。 这意味着列宽会自动扩展以填充未被第一列占据的可用空间。行以相似的方式进行定义。

    下图显示网格如何划分应用的主页面:

    主页面网格

  3. 接下来,使用 CSS 的自适应布局示例通过将每个项分配到网格中的某个特定单元格来设置 UI 项的位置。要这样做,该示例会将 -ms-grid-column-ms-grid-row 属性应用到该页面上的元素。CSS 网格支持几种其他属性相对于单元格边界定位项,并允许项跨越多行或多行。若要了解详细信息,请参阅网格布局

    以下 CSS 代码将示例应用的主页面的 header 元素放置在顶层网格的第 1 列第 1 行中,并允许该元素跨越网格的全部两列。 该代码还在顶层网格的第 1 列第 1 行内创建一个“子”网格。子网格用于定位构成标题(后退按钮、标题和子标题以及应用菜单)的各个项。

    header[role=banner] {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
        -ms-grid-column-span: 2;
    
        /* Child grid for positioning header items.*/
        display: -ms-grid;
        -ms-grid-columns: 120px 1fr;
        -ms-grid-rows: 1fr;
    }
    

    上述代码在以下图像中以蓝色突出显示的区域中创建了一个网格。

    示例应用的标题的子网格

    使用 CSS 的自适应布局示例使用嵌套的 div 元素来定义显示当日天气预报和十天天气预报的主页面区域:

    <div class="appViewContentMask">
        <div class="appViewContent">
            <div id="current-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/current.html', data: FluidAppLayout.Data.mountains[0].weatherData[0]}"></div>
            <div id="ten-day-page" class="page" data-win-control="WinJS.UI.HtmlControl" data-win-options="{uri: '/html/tenDay.html', data: FluidAppLayout.Data.mountains[0].weatherData}"></div>
        </div>
    </div>
    

    请注意,在上述示例中,Windows JavaScript 库 HtmlControl 控件用于动态地包含当日天气预报和十天天气预报的 HTML 页面。若要了解有关 WinJS 控件的详细信息,请参阅快速入门:添加 WinJS 控件和样式

    以下 CSS 代码将 appViewContentMask div 放置在顶层网格的第 2 列第 2 行中。它还设置属性以确保该内容填充整个网格单元格,不适合该单元格的所有内容会被隐藏。

    .appViewContentMask {
        -ms-grid-column: 2;
        -ms-grid-row: 2;
        width: 100%;
        height: 100%;
        overflow: hidden;
    
        /* Other properties omitted for clarity. */
    
    }
    

    以下 CSS 代码将 appViewContent div 转换为一个子网格,该子网格包含填充 appViewContentMask div 所定义的区域的单个单元格。使用子网格使得在视图状态更改应用的大小或方向时重排内容很容易。

    
    .appViewContent {
        width: 100%;
        height: 100%;
        display: -ms-grid;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 1fr;
    }
    

    CSS 代码将内容区域的网格分配给以蓝色突出显示的区域:

    示例应用的内容区域中的网格

定义十天天气预报的基本布局

十天天气预报是通过使用 WinJS ListView 控件管理和显示的项的集合。 每个项由一个图像和一组字符串组成,这些字符串包括日期、高温和低温、“体感”温度以及下雪的可能性:

十天天气预报中项的布局

以下 HTML 页面为十天天气预报中的项定义 UI。使用 CSS 的自适应布局示例使用 WinJS 模板和数据绑定来向 ListView 控件提供数据。本主题专注于设置你的 UI 的布局,因此我们此处不会研究模板和数据绑定。如果希望了解有关模板和数据绑定的详细信息,请参阅如何使用模板绑定数据

<body>
    <div class="tenDayPage">
        <div id="tenDayTemplate" class="tenDayTemplate" data-win-control="WinJS.Binding.Template">
            <div class="tenDayGrid">
                <div class="win-type-x-large tenDayDate" data-win-bind="innerHTML: date">
                </div>
                <div class="tenDayImg">
                    <img data-win-bind="src: imgSrc" />
                </div>
                <div class="win-type-x-large tenDayHighLow">
                    <span class="tenDayHigh" data-win-bind="innerHTML: hi"></span>
                    <span>/</span>  
                    <span class="tenDayLow" data-win-bind="innerHTML: low"></span>
                </div>
                <div class="tenDayFeelsLike">
                    <span>Feels like </span>
                    <span data-win-bind="innerHTML: feelsLike"></span>
                </div>
                <div class="tenDayChanceOfSnow">
                    <span>Chance of snow is </span>
                    <span data-win-bind="innerHTML: chanceOfSnow"></span>
                </div>
            </div>
        </div>
        <div id="tenDayListView" class="tenDayListView" data-win-control="WinJS.UI.ListView" data-win-options="{layout: {type: WinJS.UI.GridLayout}}"></div>
    </div>
</body>

请注意,上一个示例使用特别的 WinJS CSS classes for typography 为日期和高温/低温字符串设置特别大的字体大小。这是 class="win-type-x-large"tenDayDatetenDayHighLow div 元素中的含义。

该示例应用使用以下 CSS 代码来确保 TenDay.html 页面及其 ListView 控件将填充父容器(应用的主页面的内容区域)。

/* Size Page to full size of parent container */
.tenDayPage
{
    height: 100%;
}

/* List View Control */
.tenDayListView
{
    width: 100%;
    height: 100%;
}

使用 CSS 媒体查询可应用特定于视图的布局和样式

通过使用 CSS 媒体查询,你可以很容易定义不同的样式来根据窗口大小应用于你的应用中的 HTML 项。你可以为每种不同布局使用单独的媒体查询,或者你可以组合媒体查询以将相同的样式集应用于多个布局。此处我们介绍使用 CSS 的自适应布局示例用于设置其主页面和十天天气预报中的项的布局的媒体查询。

为窄布局设置主页面的布局

如果你使用示例应用,你将注意到在纵向、横向和布局大小调整为宽之间 UI 项的大小和布局变化不大。但是,将应用大小调整为宽度小于 500 像素时,你会看到如下变化:

  • 应用标题中的 UI 项变小。
  • 布局从两列和两行变为一个单列,其中标题占据第一行,而主内容区域占据第二行。

窄布局和宽布局之间的标题布局差异

这些更改是通过某个 CSS 媒体查询应用的,该媒体查询专门为窄宽度定义一组不同的样式:

@media (max-width:499px) {
    .appGrid {
        display: -ms-grid;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 120px 1fr;
        width: 100%;
        height: 100%;
    }

    header[role=banner] {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
        -ms-grid-columns: 60px 1fr;
        -ms-grid-rows: 1fr;
        display: -ms-grid;
    }

        header[role=banner] .win-backbutton {
            -ms-grid-column: 1;
            -ms-grid-row: 1;
            margin-left: 20px;
            margin-top: 75px;
        }

        header[role=banner] .titlearea {
            -ms-grid-column: 2;
            -ms-grid-row: 1;
            margin-top: 69px;
            max-width: 260px;
        }

    .appViewContentMask {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
    }

在上述 CSS 代码中,–ms-grid-columns 属性的新值会将应用的主网格 (appGrid) 从两列更改为一列。CSS 代码还为应用的标题中的项定义一个新的子网格,并将标题项放置在新网格中。最后,该代码将内容区域 (appViewContentMask) 从旧网格的第 2 列第 2 行移动到新网格的第 1 列第 2 行。

为窄布局设置十天天气预报的布局

当你将应用大小调整为宽度小于 500 像素时,你将注意到在十天天气预报中各个项的布局的变化。 当宽度大于 500 像素时,会使用单列网格在垂直方向上设置项的布局。当宽度小于 500 像素时,会使用双列网格将项切换到水平方向。

下图显示在不同布局下十天天气预报中的项的外观。

窄布局和宽布局之间的项布局差异

若要实现不同的布局,该示例使用 CSS 媒体查询基于当前视图状态应用样式。示例定义一组在所有视图状态下都常见的样式,定义另一组仅用于宽度小于 500px 时的布局:

/* Styles that are common across all view states */
    .tenDayGrid
    {
        width: 190px;
        height: 250px;
        overflow: hidden;
        padding: 10px;
        display: -ms-grid;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: (auto)[5];
    }

    .tenDayDate
    {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
    }

    .tenDayImg
    {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
    }

    .tenDayHighLow
    {
        -ms-grid-column: 1;
        -ms-grid-row: 3;
    }

    .tenDayFeelsLike
    {
        -ms-grid-column: 1;
        -ms-grid-row: 4;
    }
    .tenDayChanceOfSnow
    {
        -ms-grid-column: 1;
        -ms-grid-row: 5;
    }
}

/* Define the template for the width less than 500px */
@media (max-width:499px)
{
    .tenDayDate
    {
        font-weight: 600;
    }

    .tenDayDate > .day
    {
       font-weight: 200;
    }

    .tenDayHighLow
    {
        font-weight: 300;
    }

    .tenDayFeelsLike, .tenDayChanceOfSnow
    {
        font-weight: 300;
    }

    .tenDayGrid
    {
        width: 250px;
        height: 150px;
        overflow: hidden;
        padding: 10px;
        display: -ms-grid;
        -ms-grid-columns: auto 1fr;
        -ms-grid-rows: (auto)[4];
    }

    .tenDayDate
    {
        -ms-grid-column: 1;
        -ms-grid-row: 1;
        -ms-grid-column-span: 2;
    }

    .tenDayImg
    {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
        -ms-grid-row-span: 3;
    }

    .tenDayHighLow
    {
        -ms-grid-column: 2;
        -ms-grid-row: 2;
    }

    .tenDayFeelsLike
    {
        -ms-grid-column: 2;
        -ms-grid-row: 3;
    }
    .tenDayChanceOfSnow
    {
        -ms-grid-column: 2;
        -ms-grid-row: 4;
    }
}

如有必要,请使用 JavaScript 来处理窗口大小调整事件

最好通过使用 CSS 和媒体查询为你的应用定义尽可能多的布局。但是,有时你将需要使用 JavaScript 来处理 CSS 无法解决的布局问题。

例如,示例应用使用 WinJS ListView 控件来显示十天天气预报中的项,并根据应用宽度在列表模式和网格模式之间切换 ListView。当示例应用为 500 像素或更宽时,ListView 将使用网格模式在垂直方向上和水平方向上排列项以填充父容器。 当应用小于 500 像素时,ListView 将使用列表模式排列垂直列表中的项。

要使用 JavaScript 创建特定于视图的布局,请为窗口调整大小事件注册一个事件侦听程序。在事件侦听程序代码中,请查询 clientWidth 属性并相应地配置布局。

在以下示例中,使用 CSS 的自适应布局示例将 ListView 设置为网格模式。如果窗口宽度小于 500 像素,则 ListView 会更改为列表模式。应用的事件侦听程序侦听大小调整事件,然后查询 clientWidth 属性并相应更改 ListView。

function ready(element, options) { 
        element.winControl = this; 
        var that = this; 
        WinJS.UI.process(element).done(function () { 
            that.listView = element.querySelector(".tenDayListView").winControl; 
            var itemTemplate = element.querySelector(".tenDayTemplate"); 
            var listViewLayout = new WinJS.UI.GridLayout(); 
 
            if (document.body.clientWidth <= 499) { 
                listViewLayout = new WinJS.UI.ListLayout(); 
            } 
            else { 
                element.style.opacity = "0"; 
            } 
 
            // ... 
 
            window.addEventListener("resize", tenDayResize, false); 
        }); 
    } 
 
    function tenDayResize(e) { 
 
        var listview = document.querySelector(".tenDayListView").winControl; 
 
        if (document.body.clientWidth <= 499) { 
            if (!(listview.layout instanceof WinJS.UI.ListLayout)) { 
                listview.layout = new WinJS.UI.ListLayout(); 
            } 
        } 
        else { 
            if (listview.layout instanceof WinJS.UI.ListLayout) { 
                listview.layout = new WinJS.UI.GridLayout(); 
            } 
        } 
    } 

摘要

你现在应该了解了如何使用 HTML、CSS 和 JavaScript 来为你的应用创建在所有窗口大小下都外观良好且功能正常的流体 UI。

相关主题

使用 CSS 的自适应布局示例

CSS 媒体查询示例

Windows 8 动手实验室

开发阅读器应用

媒体查询规范

ListView 控件

Internet Explorer 10 开发人员指南