Z 深度和阴影

A gif showing four gray rectangles that are stacked diagonally, one on top of the other. The gif is animated so that shadows appear and disappear.

在 UI 中创建元素的视觉层次结构可以使 UI 易于扫描并传达需要重点关注的信息。 提升(将 UI 的所选元素推向用户的操作)通常用于在软件中实现此类层次结构。 本文介绍如何使用 Z 深度和阴影在 Windows 应用中创建提升效果。

Z 深度是在 3D 应用创建者中使用的一个术语,用于表示在 Z 轴方向上两个图面之间的距离。 它演示对象与观看者的靠近程度。 可将其概念视为类似于 X/Y 坐标,但方向为 Z。

Windows 应用程序使用阴影来表达深度并添加视觉层次。 为了实现这一点,z 轴提供了一个简单的编码路径。 但是,阴影是模拟的;它们不会以真正的 3D 意义显示。 这样我们就可以在不牺牲应用的 UI 性能的情况下获得深度感。

为何使用 Z 深度?

在现实生活中,我们往往会将视线聚焦于离我们较近的对象。 对于数字 UI,我们也可以运用这种空间本能。 例如,如果使某个元素越来越靠近用户,则用户会本能地将视线聚焦于该元素。 沿 Z 轴方向移近 z 轴时,可以在对象之间建立视觉层次结构,从而帮助用户在应用中自然高效地完成任务。

什么是阴影?

阴影是用户感受提升的一种方式。 提升的对象上面的光线会在下方图面上产生阴影。 对象越高,阴影就越大且越柔和。 UI 中提升的对象不需要有阴影,但阴影有助于表现提升。

在 Windows 应用中,应该有目的地使用阴影,而不能只是出于美观。 使用过多的阴影会减少或消除阴影吸引用户注意力的能力。

如果你使用标准控件,阴影已经被合并到你的 UI 中。 但是,可以使用 ThemeShadowDropShadow API 在 UI 中手动包含阴影。

ThemeShadow

可将 ThemeShadow 类型应用到任何 XAML 元素,以根据 X、Y、Z 坐标适当绘制阴影。

  • 它根据 z 深度值将阴影应用于元素,模拟深度。
  • 由于内置的阴影美学,使得阴影在整个应用程序中和跨应用程序保持一致。

下面介绍如何在 MenuFlyout 上实现 ThemeShadow。 MenuFlyout 有一个深度为 32 像素的内置阴影,应用于主菜单和所有嵌套菜单。

A screen shot of ThemeShadow applied to a MenuFlyout with three open, nested menus.

常用控件中的 ThemeShadow

除非另有说明,否则以下常用控件将自动使用 ThemeShadow 从 32 像素深度处投射阴影:

注意

Windows 10 版本 1903 (SDK 18362) 中引入了 ThemeShadow。 它在 Windows 11 中进行了更新,以便使用 ninegrid 影子而不是投影阴影来提高性能。

弹出窗口中的 ThemeShadow

如果你需要吸引用户的注意并让其采取快速操作,则经常会在应用的 UI 中使用弹出窗口。 这种情况就是借助阴影在应用 UI 中创建层次结构的极好例子。

在应用到弹出窗口中的任何 XAML 元素时,ThemeShadow 会自动投射阴影。 它会在其后面的应用背景内容上以及在其下面的任何其他已打开弹出窗口上投射阴影。

若要对弹出窗口使用 ThemeShadow,请使用 Shadow 属性将 ThemeShadow 应用到 XAML 元素。 然后,相对于该元素后面的其他元素提升该元素(例如,使用 Translation 属性的 Z 组件)。 对于大多数弹出窗口 UI,相对于应用背景内容的建议默认提升值为 32 个有效像素。

本示例在弹出窗口中显示一个矩形,它将阴影投射到应用背景内容及其后面的任何其他弹出窗口:

<Popup>
    <Rectangle x:Name="PopupRectangle" Fill="Lavender" Height="48" Width="96">
        <Rectangle.Shadow>
            <ThemeShadow />
        </Rectangle.Shadow>
    </Rectangle>
</Popup>
// Elevate the rectangle by 32px
PopupRectangle.Translation += new Vector3(0, 0, 32);

A single rectangular popup with a shadow.

在自定义浮出控件上禁用默认的 ThemeShadow

基于 FlyoutDatePickerFlyoutMenuFlyoutTimePickerFlyout 的控件会自动使用 ThemeShadow 来投射阴影。

如果控件内容上的默认阴影看起来不正确,你可以通过将关联 FlyoutPresenter 上的 IsDefaultShadowEnabled 属性设置为 false 来禁用默认阴影:

<Flyout>
    <Flyout.FlyoutPresenterStyle>
        <Style TargetType="FlyoutPresenter">
            <Setter Property="IsDefaultShadowEnabled" Value="False" />
        </Style>
    </Flyout.FlyoutPresenterStyle>
</Flyout>

其他元素中的 ThemeShadow

注意

从 Windows 11 开始,如果应用以 Windows SDK 版本 22000 或更高版本为目标,则 Receivers 集合将被忽略。 但是不会出现错误,并且阴影会继续生效。

一般情况下,我们建议仔细考虑是否要使用阴影,并只在阴影能够带来有意义的视觉层次结构时,才使用阴影。 但是,如果你的高级方案中有必要用到阴影,可以通过我们提供的方式从任何 UI 元素投射阴影。

若要从不在弹出窗口中的 XAML 元素投射阴影,必须在 ThemeShadow.Receivers 集合中显式指定可接收阴影的其他元素。 接收器不能是视觉树中投射器的上级。

本示例演示两个矩形,这些矩形在其后面的网格上投射阴影:

<Grid>
    <Grid.Resources>
        <ThemeShadow x:Name="SharedShadow" />
    </Grid.Resources>

    <Grid x:Name="BackgroundGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" />

    <Rectangle x:Name="Rectangle1" Height="100" Width="100" Fill="Turquoise" Shadow="{StaticResource SharedShadow}" />

    <Rectangle x:Name="Rectangle2" Height="100" Width="100" Fill="Turquoise" Shadow="{StaticResource SharedShadow}" />
</Grid>
/// Add BackgroundGrid as a shadow receiver and elevate the casting buttons above it
SharedShadow.Receivers.Add(BackgroundGrid);

Rectangle1.Translation += new Vector3(0, 0, 16);
Rectangle2.Translation += new Vector3(120, 0, 32);

Two turquoise rectangles next to each other, both with shadows.

投影

DropShadow 不提供内置阴影值,你需要自己指定。 有关示例实现,请参阅 DropShadow 类。

提示

从 Windows 11 开始,如果应用以 Windows SDK 版本 22000 或更高版本为目标,则 ThemeShadow 的行为将类似于投影。 如果你使用的是 DropShadow,则可以考虑改用 ThemeShadow。

我应该使用哪种阴影?

properties ThemeShadow DropShadow
Min SDK SDK 18362 SDK 14393
适应性
自定义 No
光源
在3D 环境中受支持 是(虽然它在 3D 环境中工作,但阴影是模拟的。)
  • 请记住,阴影的作用是提供有意义的层次结构,而不是简单的视觉处理。
  • 通常,我们建议使用 ThemeShadow,它可以提供一致的阴影值。
  • 如果有性能方面的忧虑,请限制阴影数目,使用其他视觉处理方法,或使用 DropShadow。
  • 如果通过更高级的方案实现视觉层次结构,请考虑使用其他视觉处理方法(例如颜色)。 如果需要阴影,请使用 DropShadow。