본문으로 건너뛰기

PlHeader

페이지 위쪽을 가로지르는 바입니다. 한쪽 끝에 브랜드, 다른 쪽 끝에 action, 가운데에 그 자리에 맞는 것을 놓습니다. 진짜 <header>여서 banner landmark가 됩니다.

React
tsx
import { PlButton, PlHeader } from 'plass-ui';

<PlHeader brand={<Logo />} actions={<PlButton size="sm">Sign in</PlButton>}>
  <Nav />
</PlHeader>;
dart
import 'package:plass_ui/plass_ui.dart';

PlHeader(
  brand: const <Widget>[Text('Acme')],
  actions: <Widget>[PlButton(onPressed: signIn, child: const Text('Sign in'))],
  child: navigation,
);

Props

Prop타입기본값설명
variant공통'solid' | 'glass' | 'ghost''glass'시트의 재질. 바에는 색이 들어가지 않습니다 — 위에 얹힌 것들이 자기 색을 갖고 옵니다
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'바의 높이 하한, gutter, 슬롯 사이의 공기. PlBox처럼 여기서 size는 시트의 크기입니다
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통'default' | 'compact''default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통0 | 1 | 2 | 30그림자 깊이. 0이 기본이고 평평합니다 — 헤더는 창 위쪽에 붙어 있지 떠 있지 않습니다
brandReactNode앞쪽 슬롯 — 로고, 제품 이름, 모든 페이지에서 같은 것
actionsReactNode뒤쪽 슬롯 — 계정 메뉴, 테마 스위치, 콜 투 액션. 끝 정렬로 배치되므로 버튼 여러 개에 wrapper가 필요 없습니다
align공통'start' | 'center' | 'end''start'가운데 슬롯이 어디에 앉는지. center는 남은 공간이 아니라 바 자신의 중심선에 맞춥니다
position공통'static' | 'sticky' | 'fixed''sticky'바가 페이지 스크롤 안에서 어떻게 앉는지. CSS가 쓰는 그대로입니다
dividerbooleantrue아래 가장자리에 헤어라인을 그립니다. 스크롤되는 페이지 위에 고정된 바는 아래로 늘 내용이 지나가므로 기본으로 켜져 있습니다
maxWidthPlassResponsive<'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'none' | number | string>'none'시트는 창을 가로지른 채로, 슬롯의 행만 measure에 맞춰 가운데 둡니다. PlContainer의 maxWidth와 같은 사다리입니다
paddedbooleantrue행 양쪽의 gutter
labelstring바가 불리는 이름. 페이지에 <header>가 둘 이상일 때 써 둘 값어치가 있습니다
renderuseRender.RenderProp<header> 대신 다른 요소로 렌더링합니다. 대개 원하는 것이 아닙니다 — 페이지 위쪽의 바는 banner이고, 그걸 말해 주는 것이 태그입니다
childrenReactNode가운데 슬롯
Prop타입기본값설명
variant공통PlassVariantPlassVariant.glass시트의 재질. 바에는 색이 들어가지 않습니다 — 위에 얹힌 것들이 자기 색을 갖고 옵니다
size공통PlassSizePlassSize.md바의 높이 하한, gutter, 슬롯 사이의 공기. PlBox처럼 여기서 size는 시트의 크기입니다
color공통PlassColorPlassColor.primary의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통PlassDensityPlassDensity.standard여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통int0그림자 깊이. 0이 기본이고 평평합니다 — 헤더는 창 위쪽에 붙어 있지 떠 있지 않습니다
brandList<Widget>?앞쪽 슬롯 — 로고, 제품 이름. 슬롯은 행이므로 리스트입니다. 로고와 그 옆 이름 사이의 간격은 바가 정합니다
actionsList<Widget>?뒤쪽 슬롯 — 계정 메뉴, 테마 스위치, 콜 투 액션. 끝 정렬로 배치되므로 버튼 여러 개에 wrapper가 필요 없습니다
align공통PlassAlignPlassAlign.start가운데 슬롯이 어디에 앉는지. center는 남은 공간이 아니라 바 자신의 중심선에 맞춥니다
dividerbooltrue아래 가장자리에 헤어라인을 그립니다. 스크롤되는 페이지 위에 고정된 바는 아래로 늘 내용이 지나가므로 기본으로 켜져 있습니다
maxWidthPlassResponsive<PlContainerWidth?>?null내용이 넓어질 수 있는 한계. PlContainerWidth.rung(PlassSize)는 사다리 한 칸, PlContainerWidth.pixels(double)는 정확한 너비입니다. null은 제한 없음이고, 항목으로 써도 그렇습니다
paddedbooltrue행 양쪽의 gutter
semanticLabelString?스크린 리더가 바를 부르는 이름. 이름을 주면 landmark(region)가 되고, 없으면 아무것도 주장하지 않습니다 — 라벨 없는 region은 아무것도 설명하지 못한다는 프레임워크의 규칙입니다
childWidget?가운데 슬롯

네이티브 <header> 속성은 모두 그대로 전달됩니다. colortitle은 여기서 Plass의 prop이라 제외됩니다.

brandactions는 위젯 하나가 아니라 리스트입니다. 슬롯이 곧 행이기 때문입니다. 로고와 그 옆 이름 사이의 간격은 바가 정합니다. PlToolbar도 양 끝을 같은 모양으로 씁니다.

공용 축(variant size color density elevation)이 라이브러리 전체에서 무엇을 뜻하는지는 prop 규약에 있습니다.

PlHeader와 PlToolbar

PlToolbar는 화면 어디에나 놓이는 컨트롤의 행이고, 높이는 padding만으로 정해집니다. header는 페이지의 banner입니다. 높이 하한, measure, brand 슬롯, 그리고 PlPageLayout 안의 자리를 갖는데, 표 옆에 놓인 컨트롤 행에는 그중 어느 것도 뜻이 없습니다.

가진 것이 컨트롤이면 toolbar를, 가진 것이 페이지의 꼭대기면 이것을 쓰세요.

Examples

세 슬롯

brand, children, actions 순서입니다. 하위 컴포넌트가 아니라 prop인 이유는 PlCard와 같습니다. 배치는 정해져 있고, 호출하는 쪽이 정하는 것은 각 자리에 무엇이 들어가느냐입니다.

비어 있는 슬롯은 아무것도 그리지 않습니다. brand만 있는 header는 영역 셋이 아니라 하나입니다.

align

가운데가 어디에 앉는지입니다. start는 brand 쪽으로 붙이고 기본값이며, end는 actions 쪽으로 붙입니다.

설명할 값어치가 있는 것은 center입니다. 남은 공간의 가운데에 두면 brand가 끝나는 자리에 따라 위치가 정해져서, 로고가 한 글자 길어지면 내비게이션이 움직입니다. 같은 사이트의 두 페이지 사이에서 독자가 정확히 알아채는 것이 그것입니다. 그래서 양 끝에 같은 몫을 주고, 그러면 안에 무엇이 있든 가운데는 바 자신의 중심선에 놓입니다. 비어 있는 끝도 자기 절반을 차지합니다.

React

position

기본은 sticky입니다. 페이지가 거기까지 스크롤되면 바가 창 위쪽에 붙고, 흐름 안에 남아 있으므로 아래의 무엇도 밀어낼 필요가 없습니다.

fixed는 흐름 밖으로 완전히 빼냅니다. PlPageLayout 안이라면 레이아웃이 바의 높이를 대신 비워 둡니다. static은 페이지와 함께 스크롤되어 지나가게 둡니다.

variant

세 재질을 컨테이너로 읽은 것입니다. 바에는 색이 들어가지 않습니다. 위에 얹히는 것(chip, button, avatar)이 자기 색을 갖고 오기 때문에, 색이 든 시트는 그 모두를 자기가 고려되지 않은 배경 위에 올려놓게 됩니다.

divider는 기본으로 켜져 있고, 실제로 바를 콘텐츠에서 떼어 놓는 것이 그것입니다. 스크롤되는 페이지 위에 고정된 반투명 시트는 아래로 늘 내용이 지나가는데, 가장자리를 표시하는 것이 없으면 그 일부처럼 읽힙니다.

React

size

바의 하한은 같은 size의 컨트롤에 위아래 공기를 더한 것입니다. md는 64px이고, 40px 컨트롤에 양쪽 12px입니다. 높이가 아니라 하한이므로, 내용이 줄바꿈되는 바는 커지면서 padding을 유지합니다.

density는 라이브러리의 다른 곳과 똑같이 gutter만 옮깁니다.

React

maxWidth

시트는 창을 가로지른 채로, 슬롯의 행만 measure에 맞춰 가운데 둡니다. 넓은 화면의 사이트 헤더가 거의 언제나 원하는 것입니다.

PlContainer와 같은 사다리, 같은 타입이고 셋 뒤에 구현이 하나입니다. 아래 컨테이너와 measure가 어긋나는 바가 그것이 막는 결함입니다. 반응형이고 아무 CSS 길이나 함께 받습니다.반응형이고, 사다리 한 칸뿐 아니라 정확한 너비도 받습니다.

PlContainermaxWidth와 같은 rem 사다리(xs 30 · sm 40 · md 48 · lg 64 · xl 80)이므로, 로고와 그 아래 페이지의 첫 문단이 거의 같은 두 줄이 아니라 하나의 선 위에 놓입니다.

React

PlPageLayout 안에서

header는 레이아웃에 자신을 등록하고, 레이아웃은 그것을 재서 창에서 얼마를 가져가는지 자기 root에 씁니다. 자기 자리를 지키는 sidebar가, 그 높이를 바 말고는 아무도 모르는 바 아래에서 시작할 수 있는 이유가 그것입니다.

이를 위해 넘겨야 할 것은 없습니다. 레이아웃 밖에서는 등록이 아무 데도 가지 않고, 바는 그냥 바입니다.

넘겨야 할 것도, 재야 할 것도 없습니다. 레이아웃의 Column이 이미 header가 가져가지 않은 만큼을 band에 남겨 두었으므로, 그 옆의 sidebar는 구조상 바 아래에서 시작합니다.

React 빌드와 다른 점

ReactFlutter이유
positionfixedsticky는 무언가를 기준으로 삼아야 합니다. 위젯은 화면이 두는 자리에 정확히 놓이고, 고정되어야 하는 바는 화면 자신의 레이아웃에 속합니다.
레이아웃에 등록Column이 이미 그 산수를 끝냈습니다. 어디에도 쓸 높이가 없습니다.
노드 하나인 brand, actionsList<Widget>슬롯이 곧 행이고, 그 안의 간격은 바가 정합니다. PlToolbar와 같은 모양입니다.
maxWidth: 'none'maxWidth: null"measure를 정하지 않았다"를 Dart가 나타내는 방식입니다.
<header>, banner landmarksemanticLabelregion roleFlutter semantics에는 banner role이 없습니다. 이름이 있는 바는 region이고, 이름이 없으면 아무 role도 선언하지 않습니다. 라벨 없는 region은 아무것도 설명하지 못하기 때문입니다.
labelsemanticLabelFlutter의 이름이고, 여기서는 하나를 더 합니다. 바를 landmark로 만드는 것이 그것입니다.
render바꿀 태그가 없습니다.
className, style, 네이티브 속성전달할 class 목록도 style 속성도 없습니다.

Accessibility

  • 진짜 <header>를 그립니다. 문서의 최상위에서 그것은 banner landmark이고, 스크린 리더의 landmark 목록, 리더 모드, 검색 엔진이 모두 그것을 읽습니다.
  • label이 바의 이름입니다. 페이지에 두 개가 있을 때 써 둘 값어치가 있습니다. "banner"가 두 번 나오면 어느 쪽이 어느 쪽인지 전혀 알려 주지 못하기 때문입니다.
  • 바는 role="toolbar"role="navigation"도 선언하지 않습니다. 앞의 것은 구현하지 않은 키보드 동작에 대한 약속이고, 뒤의 것은 호출하는 쪽이 가운데 슬롯에 넣는 <nav>의 몫입니다.
  • 슬롯은 배치되지만 순서가 바뀌지는 않으므로, 읽는 순서는 쓴 순서 그대로입니다.
  • semanticLabel이 바의 이름이고, 그것이 바를 region landmark로 만듭니다. 이름이 없으면 바는 아무것도 주장하지 않는데, 의도된 것입니다. Flutter는 라벨 없는 region을 거부합니다. 이름 붙일 수 없는 landmark는 건너뛸 수도 없는 landmark이기 때문입니다.
  • 대신 선언할 banner role은 없습니다. 이름 있는 region이 가장 참에 가까운 것이고, 프레임워크에 없는 role을 선언하는 것은 아무것도 주장하지 않는 것보다 나쁩니다.
  • 바는 toolbar semantics를 선언하지 않습니다. 구현하지 않은 키보드 동작에 대한 약속이기 때문입니다.
  • 슬롯은 배치되지만 순서가 바뀌지는 않으므로, 순회 순서는 쓴 순서 그대로입니다.

Released under the MIT License