Layout
Handling the overall layout of a page.
Specification#
Size#
The first level navigation is left aligned near a logo, and the secondary menu is right aligned.
Top Navigation: the height of the first level navigation
64px
, the second level navigation48px
.Top Navigation (for landing pages): the height of the first level navigation
80px
, the second level navigation56px
.Calculation formula of a top navigation:
48+8n
.Calculation formula of an aside navigation:
200+8n
.
Interaction rules#
The first level navigation and the last level navigation should be distinguishable by visualization;
The current item should have the highest priority of visualization;
When the current navigation item is collapsed, the style of the current navigation item is applied to its parent level;
The left side navigation bar has support for both the accordion and expanding styles; you can choose the one that fits your case the best.
Visualization rules#
Style of a navigation should conform to its level.
Emphasis by colorblock
When background color is a deep color, you can use this pattern for the parent level navigation item of the current page.
The highlight match stick
When background color is a light color, you can use this pattern for the current page navigation item; we recommend using it for the last item of the navigation path.
Highlighted font
From the visualization aspect, a highlighted font is stronger than colorblock; this pattern is often used for the parent level of the current item.
Enlarge the size of the font
12px
,14px
is a standard font size of navigations,14px
is used for the first and the second level of the navigation. You can choose an appropriate font size regarding the level of your navigation.
Component Overview#
Layout
: The layout wrapper, in whichHeader
Sider
Content
Footer
orLayout
itself can be nested, and can be placed in any parent container.Header
: The top layout with the default style, in which any element can be nested, and must be placed inLayout
.Sider
: The sidebar with default style and basic functions, in which any element can be nested, and must be placed inLayout
.Content
: The content layout with the default style, in which any element can be nested, and must be placed inLayout
.Footer
: The bottom layout with the default style, in which any element can be nested, and must be placed inLayout
.
Based on
flex layout
, please pay attention to the compatibility.
Examples
import { Layout } from 'infrad';
import React from 'react';
const { Header, Footer, Sider, Content } = Layout;
const App: React.FC = () => (
<>
<Layout>
<Header>Header</Header>
<Content>Content</Content>
<Footer>Footer</Footer>
</Layout>
<Layout>
<Header>Header</Header>
<Layout>
<Sider>Sider</Sider>
<Content>Content</Content>
</Layout>
<Footer>Footer</Footer>
</Layout>
<Layout>
<Header>Header</Header>
<Layout>
<Content>Content</Content>
<Sider>Sider</Sider>
</Layout>
<Footer>Footer</Footer>
</Layout>
<Layout>
<Sider>Sider</Sider>
<Layout>
<Header>Header</Header>
<Content>Content</Content>
<Footer>Footer</Footer>
</Layout>
</Layout>
</>
);
export default App;
import { Breadcrumb, Layout, Menu } from 'infrad';
import React from 'react';
const { Header, Content, Footer } = Layout;
const App: React.FC = () => (
<Layout className="layout">
<Header>
<div className="logo" />
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['2']}
items={new Array(15).fill(null).map((_, index) => {
const key = index + 1;
return {
key,
label: `nav ${key}`,
};
})}
/>
</Header>
<Content style={{ padding: '0 50px' }}>
<Breadcrumb style={{ margin: '16px 0' }}>
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item>List</Breadcrumb.Item>
<Breadcrumb.Item>App</Breadcrumb.Item>
</Breadcrumb>
<div className="site-layout-content">Content</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Infra Design ©2018 Created by Ant UED</Footer>
</Layout>
);
export default App;
.site-layout-content {
min-height: 280px;
padding: 24px;
background: #fff;
}
#components-layout-demo-top .logo {
float: left;
width: 120px;
height: 31px;
margin: 16px 24px 16px 0;
background: rgba(255, 255, 255, 0.3);
}
.ant-row-rtl #components-layout-demo-top .logo {
float: right;
margin: 16px 0 16px 24px;
}
import { LaptopOutlined, NotificationOutlined, UserOutlined } from 'infra-design-icons';
import type { MenuProps } from 'infrad';
import { Breadcrumb, Layout, Menu } from 'infrad';
import React from 'react';
const { Header, Content, Sider } = Layout;
const items1: MenuProps['items'] = ['1', '2', '3'].map(key => ({
key,
label: `nav ${key}`,
}));
const items2: MenuProps['items'] = [UserOutlined, LaptopOutlined, NotificationOutlined].map(
(icon, index) => {
const key = String(index + 1);
return {
key: `sub${key}`,
icon: React.createElement(icon),
label: `subnav ${key}`,
children: new Array(4).fill(null).map((_, j) => {
const subKey = index * 4 + j + 1;
return {
key: subKey,
label: `option${subKey}`,
};
}),
};
},
);
const App: React.FC = () => (
<Layout>
<Header className="header">
<div className="logo" />
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']} items={items1} />
</Header>
<Layout>
<Sider width={200} className="site-layout-background">
<Menu
mode="inline"
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
style={{ height: '100%', borderRight: 0 }}
items={items2}
/>
</Sider>
<Layout style={{ padding: '0 32px 32px' }}>
<Breadcrumb style={{ margin: '16px 0' }}>
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item>List</Breadcrumb.Item>
<Breadcrumb.Item>App</Breadcrumb.Item>
</Breadcrumb>
<Content
className="site-layout-background"
style={{
padding: 24,
margin: 0,
minHeight: 280,
}}
>
Content
</Content>
</Layout>
</Layout>
</Layout>
);
export default App;
#components-layout-demo-top-side-2 .logo {
float: left;
width: 120px;
height: 31px;
margin: 16px 24px 16px 0;
background: rgba(255, 255, 255, 0.3);
}
.ant-row-rtl #components-layout-demo-top-side-2 .logo {
float: right;
margin: 16px 0 16px 24px;
}
.site-layout-background {
background: #fff;
}
import { LaptopOutlined, NotificationOutlined, UserOutlined } from 'infra-design-icons';
import type { MenuProps } from 'infrad';
import { Breadcrumb, Layout, Menu } from 'infrad';
import React from 'react';
const { Header, Content, Footer, Sider } = Layout;
const items1: MenuProps['items'] = ['1', '2', '3'].map(key => ({
key,
label: `nav ${key}`,
}));
const items2: MenuProps['items'] = [UserOutlined, LaptopOutlined, NotificationOutlined].map(
(icon, index) => {
const key = String(index + 1);
return {
key: `sub${key}`,
icon: React.createElement(icon),
label: `subnav ${key}`,
children: new Array(4).fill(null).map((_, j) => {
const subKey = index * 4 + j + 1;
return {
key: subKey,
label: `option${subKey}`,
};
}),
};
},
);
const App: React.FC = () => (
<Layout>
<Header className="header">
<div className="logo" />
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']} items={items1} />
</Header>
<Content style={{ padding: '0 50px' }}>
<Breadcrumb style={{ margin: '16px 0' }}>
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item>List</Breadcrumb.Item>
<Breadcrumb.Item>App</Breadcrumb.Item>
</Breadcrumb>
<Layout className="site-layout-background" style={{ padding: '24px 0' }}>
<Sider className="site-layout-background" width={200}>
<Menu
mode="inline"
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
style={{ height: '100%' }}
items={items2}
/>
</Sider>
<Content style={{ padding: '0 24px', minHeight: 280 }}>Content</Content>
</Layout>
</Content>
<Footer style={{ textAlign: 'center' }}>Infra Design ©2018 Created by Ant UED</Footer>
</Layout>
);
export default App;
#components-layout-demo-top-side .logo {
float: left;
width: 120px;
height: 31px;
margin: 16px 24px 16px 0;
background: rgba(255, 255, 255, 0.3);
}
.ant-row-rtl #components-layout-demo-top-side .logo {
float: right;
margin: 16px 0 16px 24px;
}
.site-layout-background {
background: #fff;
}
import {
DesktopOutlined,
FileOutlined,
PieChartOutlined,
TeamOutlined,
UserOutlined,
} from 'infra-design-icons';
import type { MenuProps } from 'infrad';
import { Breadcrumb, Layout, Menu } from 'infrad';
import React, { useState } from 'react';
const { Header, Content, Footer, Sider } = Layout;
type MenuItem = Required<MenuProps>['items'][number];
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
): MenuItem {
return {
key,
icon,
children,
label,
} as MenuItem;
}
const items: MenuItem[] = [
getItem('Option 1', '1', <PieChartOutlined />),
getItem('Option 2', '2', <DesktopOutlined />),
getItem('User', 'sub1', <UserOutlined />, [
getItem('Tom', '3'),
getItem('Bill', '4'),
getItem('Alex', '5'),
]),
getItem('Team', 'sub2', <TeamOutlined />, [getItem('Team 1', '6'), getItem('Team 2', '8')]),
getItem('Files', '9', <FileOutlined />),
];
const App: React.FC = () => {
const [collapsed, setCollapsed] = useState(false);
return (
<Layout style={{ minHeight: '100vh' }}>
<Sider collapsible collapsed={collapsed} onCollapse={value => setCollapsed(value)}>
<div className="logo" />
<Menu theme="dark" defaultSelectedKeys={['1']} mode="inline" items={items} />
</Sider>
<Layout className="site-layout">
<Header className="site-layout-background" style={{ padding: 0 }} />
<Content style={{ margin: '0 16px' }}>
<Breadcrumb style={{ margin: '16px 0' }}>
<Breadcrumb.Item>User</Breadcrumb.Item>
<Breadcrumb.Item>Bill</Breadcrumb.Item>
</Breadcrumb>
<div className="site-layout-background" style={{ padding: 24, minHeight: 360 }}>
Bill is a cat.
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
</Layout>
</Layout>
);
};
export default App;
#components-layout-demo-side .logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.3);
}
.site-layout .site-layout-background {
background: #fff;
}
import {
MenuFoldOutlined,
MenuUnfoldOutlined,
UploadOutlined,
UserOutlined,
VideoCameraOutlined,
} from 'infra-design-icons';
import { Layout, Menu } from 'infrad';
import React, { useState } from 'react';
const { Header, Sider, Content } = Layout;
const App: React.FC = () => {
const [collapsed, setCollapsed] = useState(false);
return (
<Layout>
<Sider trigger={null} collapsible collapsed={collapsed}>
<div className="logo" />
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['1']}
items={[
{
key: '1',
icon: <UserOutlined />,
label: 'nav 1',
},
{
key: '2',
icon: <VideoCameraOutlined />,
label: 'nav 2',
},
{
key: '3',
icon: <UploadOutlined />,
label: 'nav 3',
},
]}
/>
</Sider>
<Layout className="site-layout">
<Header className="site-layout-background" style={{ padding: 0 }}>
{React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
className: 'trigger',
onClick: () => setCollapsed(!collapsed),
})}
</Header>
<Content
className="site-layout-background"
style={{
margin: '24px 16px',
padding: 24,
minHeight: 280,
}}
>
Content
</Content>
</Layout>
</Layout>
);
};
export default App;
#components-layout-demo-custom-trigger .trigger {
padding: 0 24px;
font-size: 18px;
line-height: 64px;
cursor: pointer;
transition: color 0.3s;
}
#components-layout-demo-custom-trigger .trigger:hover {
color: #2673dd;
}
#components-layout-demo-custom-trigger .logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.3);
}
.site-layout .site-layout-background {
background: #fff;
}
import { UploadOutlined, UserOutlined, VideoCameraOutlined } from 'infra-design-icons';
import { Layout, Menu } from 'infrad';
import React from 'react';
const { Header, Content, Footer, Sider } = Layout;
const App: React.FC = () => (
<Layout>
<Sider
breakpoint="lg"
collapsedWidth="0"
onBreakpoint={broken => {
console.log(broken);
}}
onCollapse={(collapsed, type) => {
console.log(collapsed, type);
}}
>
<div className="logo" />
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['4']}
items={[UserOutlined, VideoCameraOutlined, UploadOutlined, UserOutlined].map(
(icon, index) => ({
key: String(index + 1),
icon: React.createElement(icon),
label: `nav ${index + 1}`,
}),
)}
/>
</Sider>
<Layout>
<Header className="site-layout-sub-header-background" style={{ padding: 0 }} />
<Content style={{ margin: '24px 16px 0' }}>
<div className="site-layout-background" style={{ padding: 24, minHeight: 360 }}>
content
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Infra Design ©2018 Created by Ant UED</Footer>
</Layout>
</Layout>
);
export default App;
#components-layout-demo-responsive .logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.2);
}
.site-layout-sub-header-background {
background: #fff;
}
.site-layout-background {
background: #fff;
}
import { Breadcrumb, Layout, Menu } from 'infrad';
import React from 'react';
const { Header, Content, Footer } = Layout;
const App: React.FC = () => (
<Layout>
<Header style={{ position: 'fixed', zIndex: 1, width: '100%' }}>
<div className="logo" />
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['2']}
items={new Array(3).fill(null).map((_, index) => ({
key: String(index + 1),
label: `nav ${index + 1}`,
}))}
/>
</Header>
<Content className="site-layout" style={{ padding: '0 50px', marginTop: 64 }}>
<Breadcrumb style={{ margin: '16px 0' }}>
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item>List</Breadcrumb.Item>
<Breadcrumb.Item>App</Breadcrumb.Item>
</Breadcrumb>
<div className="site-layout-background" style={{ padding: 24, minHeight: 380 }}>
Content
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Infra Design ©2018 Created by Ant UED</Footer>
</Layout>
);
export default App;
#components-layout-demo-fixed .logo {
float: left;
width: 120px;
height: 31px;
margin: 16px 24px 16px 0;
background: rgba(255, 255, 255, 0.2);
}
.site-layout .site-layout-background {
background: #fff;
}
import {
AppstoreOutlined,
BarChartOutlined,
CloudOutlined,
ShopOutlined,
TeamOutlined,
UploadOutlined,
UserOutlined,
VideoCameraOutlined,
} from 'infra-design-icons';
import type { MenuProps } from 'infrad';
import { Layout, Menu } from 'infrad';
import React from 'react';
const { Header, Content, Footer, Sider } = Layout;
const items: MenuProps['items'] = [
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
BarChartOutlined,
CloudOutlined,
AppstoreOutlined,
TeamOutlined,
ShopOutlined,
].map((icon, index) => ({
key: String(index + 1),
icon: React.createElement(icon),
label: `nav ${index + 1}`,
}));
const App: React.FC = () => (
<Layout hasSider>
<Sider
style={{
overflow: 'auto',
height: '100vh',
position: 'fixed',
left: 0,
top: 0,
bottom: 0,
}}
>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['4']} items={items} />
</Sider>
<Layout className="site-layout" style={{ marginLeft: 200 }}>
<Header className="site-layout-background" style={{ padding: 0 }} />
<Content style={{ margin: '24px 16px 0', overflow: 'initial' }}>
<div className="site-layout-background" style={{ padding: 24, textAlign: 'center' }}>
...
<br />
Really
<br />
...
<br />
...
<br />
...
<br />
long
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
...
<br />
content
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Infra Design ©2018 Created by Ant UED</Footer>
</Layout>
</Layout>
);
export default App;
#components-layout-demo-fixed-sider .logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.2);
}
.site-layout .site-layout-background {
background: #fff;
}
API#
<Layout>
<Header>header</Header>
<Layout>
<Sider>left sidebar</Sider>
<Content>main content</Content>
<Sider>right sidebar</Sider>
</Layout>
<Footer>footer</Footer>
</Layout>
Layout#
The wrapper.
Property | Description | Type | Default |
---|---|---|---|
className | Container className | string | - |
hasSider | Whether contain Sider in children, don't have to assign it normally. Useful in ssr avoid style flickering | boolean | - |
style | To customize the styles | CSSProperties | - |
Layout.Sider#
The sidebar.
Property | Description | Type | Default |
---|---|---|---|
breakpoint | Breakpoints of the responsive layout | xs | sm | md | lg | xl | xxl | - |
className | Container className | string | - |
collapsed | To set the current status | boolean | - |
collapsedWidth | Width of the collapsed sidebar, by setting to 0 a special trigger will appear | number | 80 |
collapsible | Whether can be collapsed | boolean | false |
defaultCollapsed | To set the initial status | boolean | false |
reverseArrow | Reverse direction of arrow, for a sider that expands from the right | boolean | false |
style | To customize the styles | CSSProperties | - |
theme | Color theme of the sidebar | light | dark | dark |
trigger | Specify the customized trigger, set to null to hide the trigger | ReactNode | - |
width | Width of the sidebar | number | string | 200 |
zeroWidthTriggerStyle | To customize the styles of the special trigger that appears when collapsedWidth is 0 | object | - |
onBreakpoint | The callback function, executed when breakpoints changed | (broken) => {} | - |
onCollapse | The callback function, executed by clicking the trigger or activating the responsive layout | (collapsed, type) => {} | - |
breakpoint width#
{
xs: '480px',
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px',
xxl: '1600px',
}