Office UI Fabric 的布局问题
Layout problems with Office UI Fabric
[编辑:更新以将问题集中在覆盖问题上;还对 CodePens 进行了编辑]
[EDIT2:更新以包含有关 Mohamed Mansour 建议的方法的详细信息]
我在设计 Office UI Fabric React UI 的布局时遇到困难。这是我目前的布局:
目标是将顶部的 CommandBar 和 headers(文本标签和搜索框)固定在顶部,DetailsList 和归档按钮固定在底部并占据尽可能多的空间 space 尽可能在 header 区域之后。
我已成功使用 ScrollablePane 和两个 Sticky 组件将 CommandBar 和按钮固定在所需位置。但是,DetailsList 滚动到包含 CommandBar 和 header 的顶部 Sticky,按钮略微覆盖在 DetailsList 网格的顶部:
我试过使用 Fabric Grid 组件来布置所有部分,但它没有什么不同(如果它有帮助的话)。最好的布局是在两个 Sticky 元素之间放置项目部分;如果将项目部分添加到 Header 或 Footer Sticky 元素中的任何一个,则布局很糟糕。如何确保 DetailsList 不会在顶部和底部组件下方滚动?
这里有两支代码笔可以说明问题:
无网格:https://codepen.io/elegault/pen/aQayvY?editors=0010(文件Header为其元素使用网格,但所有其他元素不在网格中)
const columns = [{
key: 'projectNameColumn',
name: 'Project',
fieldName: 'name',
minWidth: 100,
maxWidth: 200,
isResizable: true,
ariaLabel: 'Operations for Project'
}];
const items = [{
id: '0',
name: 'ABC Construction'
},
{
id: '1',
name: 'Air Bee and Bee'
},
{
id: '2',
name: 'Architectural Salvage'
},
{
id: '3',
name: 'Arkham Airport'
},
{
id: '4',
name: 'Arkham Assembly Hall'
},
{
id: '5',
name: 'Arkham Library'
},
{
id: '6',
name: 'zArkham Renovation'
},
{
id: '7',
name: 'Foo'
},
{
id: '8',
name: 'Foo1'
},
{
id: '9',
name: 'Foo2'
},
{
id: '10',
name: 'Foo3'
},
{
id: '11',
name: 'Foo4'
},
{
id: '12',
name: 'Foo5'
},
{
id: '13',
name: 'Foo6'
},
{
id: '14',
name: 'Foo7'
},
{
id: '15',
name: 'Foo8'
},
{
id: '16',
name: 'Foo9'
},
{
id: '17',
name: 'Foo10'
},
];
class Content extends React.Component {
public render() {
const fileHeader = <
div className = 'ms-Grid' >
<
div className = 'ms-Grid-row' >
<
div className = 'ms-Grid-col ms-sm2 ms-md2 ms-lg2' >
<
img width = '32'
height = '32'
alt = 'logo'
title = 'logo' / >
<
/div> <
div className = 'ms-Grid-col ms-sm10 ms-md10 ms-lg10' >
<
Fabric.Label className = 'ms-font-l ms-fontWeight-bold ms-fontColor-blue' > [TITLE] < /Fabric.Label> <
/div> <
/div> <
div className = 'ms-Grid-row' >
<
div className = 'ms-Grid-col ms-sm2 ms-md2 ms-lg2' >
<
/div> <
div className = 'ms-Grid-col ms-sm10 ms-md10 ms-lg10' >
<
Fabric.Label
className = 'ms-font-m ms-fontWeight-bold ms-fontColor-neutralPrimary' > SELECTED PROJECT: < /Fabric.Label> <
/div> <
/div> <
/div>;
const commandBar = < div >
<
Fabric.CommandBar
isSearchBoxVisible = {
false
}
items = {
[{
key: 'openWebApp',
name: 'Open Web App',
icon: 'OpenInNewWindow', // Or Link
['data-automation-id']: 'openWebAppButton',
title: 'Open web app',
href: 'http://www.codepen.io',
target: '_blank',
}]
}
farItems = {
[{
key: 'menuOptions',
name: 'Options',
icon: 'Settings',
iconOnly: 'true',
['data-automation-id']: 'settingsButton',
subMenuProps: {
items: [{
key: 'privacyPolicy',
name: 'Privacy Policy',
icon: 'PageLock',
href: 'http://www.codepen.io',
target: '_blank',
},
{
key: 'termsOfUse',
name: 'Terms & Conditions',
icon: 'TextDocument',
href: 'http://www.codepen.io',
target: '_blank'
}
]
}
}]
}
/> <
/div>;
const projects = < Fabric.MarqueeSelection selection = {
null
}
data - is - scrollable = {
false
} >
<
Fabric.DetailsList
items = {
items
}
columns = {
columns
}
/> <
/Fabric.MarqueeSelection>;
const selection = < div > [project name] < /div>;
const search = < Fabric.TextField label = 'Search projects:' / > ;
const fileButton = <
div >
<
Fabric.DefaultButton primary = {
true
} > File To Project < /Fabric.DefaultButton> <
/div>;
return ( <
Fabric.Fabric >
<
div style = {
{
height: '500px',
position: 'relative',
maxHeight: 'inherit'
}
} >
<
Fabric.ScrollablePane scrollbarVisibility = {
Fabric.ScrollbarVisibility.auto
} >
<
Fabric.Sticky stickyPosition = {
Fabric.StickyPositionType.Header
} > {
commandBar
} {
fileHeader
} {
selection
} {
search
} <
/Fabric.Sticky> {
projects
} <
Fabric.Sticky stickyPosition = {
Fabric.StickyPositionType.Footer
} > {
fileButton
} <
/Fabric.Sticky> <
/Fabric.ScrollablePane> <
/div> <
/Fabric.Fabric>
);
}
}
ReactDOM.render( <
Content / > ,
document.getElementById('content')
);
完整网格:https://codepen.io/elegault/pen/wQxoRR
const columns = [
{
key: 'projectNameColumn',
name: 'Project',
fieldName: 'name',
minWidth: 100,
maxWidth: 200,
isResizable: true,
ariaLabel: 'Operations for Project'
}
];
const items = [
{id: '0', name: 'ABC Construction'},
{id: '1', name: 'Air Bee and Bee'},
{id: '2', name: 'Architectural Salvage'},
{id: '3', name: 'Arkham Airport'},
{id: '4', name: 'Arkham Assembly Hall'},
{id: '5', name: 'Arkham Library'},
{id: '6', name: 'zArkham Renovation'},
{id: '7', name: 'Foo'},
{id: '8', name: 'Foo1'},
{id: '9', name: 'Foo2'},
{id: '10', name: 'Foo3'},
{id: '11', name: 'Foo4'},
{id: '12', name: 'Foo5'},
{id: '13', name: 'Foo6'},
{id: '14', name: 'Foo7'},
{id: '15', name: 'Foo8'},
{id: '16', name: 'Foo9'},
{id: '17', name: 'Foo10'},
];
class Content extends React.Component {
public render() {
const commandBar = <div>
<Fabric.CommandBar
isSearchBoxVisible={false}
items={[
{
key: 'openWebApp',
name: 'Open Web App',
icon: 'OpenInNewWindow', // Or Link
title: 'Open web app',
href: 'http://www.codepen.io',
target: '_blank',
}
]}
farItems={[
{
key: 'menuOptions',
name: 'Options',
icon: 'Settings',
iconOnly: 'true',
['data-automation-id']: 'settingsButton',
subMenuProps: {
items: [
{
key: 'privacyPolicy',
name: 'Privacy Policy',
icon: 'PageLock',
href: 'http://www.codepen.io',
target: '_blank',
},
{
key: 'termsOfUse',
name: 'Terms & Conditions',
icon: 'TextDocument',
href: 'http://www.codepen.io',
target: '_blank'
}
]
}
}
]}
/>
</div>;
const projects = <Fabric.MarqueeSelection selection={null} data-is-scrollable={false}>
<Fabric.DetailsList
items={items}
columns={columns}
/>
</Fabric.MarqueeSelection>;
const selection = <div>[project name]</div>;
const search = <Fabric.TextField label='Search projects:'/>;
const fileButton =
<div>
<Fabric.DefaultButton primary={true}>File To Project</Fabric.DefaultButton>
</div>;
const fileHeader =
<div className='ms-Grid'>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm2 ms-md2 ms-lg2'>
<img width='32' height='32' alt='logo' title='logo'/>
</div>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
<Fabric.Label className='ms-font-l ms-fontWeight-bold ms-fontColor-blue'>[TITLE]</Fabric.Label>
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm2 ms-md2 ms-lg2'>
</div>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
<Fabric.Label
className='ms-font-m ms-fontWeight-bold ms-fontColor-neutralPrimary'>SELECTED PROJECT:</Fabric.Label>
</div>
</div>
</div>;
return (
<Fabric.Fabric>
<div style={{height:'500px', position:'relative', maxHeight:'inherit'}}>
<Fabric.ScrollablePane scrollbarVisibility={Fabric.ScrollbarVisibility.auto}>
<div className='ms-Grid'>
<Fabric.Sticky stickyPosition={Fabric.StickyPositionType.Header}>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{commandBar}
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{fileHeader}
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{selection}
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{search}
</div>
</div>
</Fabric.Sticky>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{projects}
</div>
</div>
<Fabric.Sticky stickyPosition={Fabric.StickyPositionType.Footer}>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{fileButton}
</div>
</div>
</Fabric.Sticky>
</div>
</Fabric.ScrollablePane>
</div>
</Fabric.Fabric>
);
}
}
ReactDOM.render(
<Content />,
document.getElementById('content')
);
此外,当尝试在使用嵌套自定义 React 组件的 codepens 之外的项目中使用 Flex 类 或在 parent div 中定义高度(根据 Mohamed Mansour 的建议)时,整个DetailsList 无法呈现。例如,这个 DOM 资源管理器显示了即使设置定义的高度并在多个 'main' div 中使用 flex 仍然无法呈现 DetailsList:
让我们澄清一些术语,这些来自文档:
- ScrollablePane:使用绝对定位,父级必须有相对和高度(来自 flex 或 static)。所以如果你想让它以你自己的方式伸展,你需要满足这些约束。
- Sticky:这些是页眉和页脚的理想选择,但仍将位于滚动条区域内。通常用于多节。
- 重叠内容: 这是完全正常的,你的页眉和页脚没有纯色背景,设置为白色,它会按预期工作。
要实现您想要的效果,让滚动条仅出现在页眉和页脚之间,您可以添加一些正常的 CSS。 运行 看下面的片段。基本上只是一个弹性布局。
我也更新了你的例子:https://codepen.io/mohamedhmansour/pen/rQqqvP
let { DetailsList, Fabric, ScrollablePane, ScrollbarVisibility } = window.Fabric;
function Content() {
const items = [...Array(500).keys()].map(i => ({key: i, text: `Item ${i}`}));
return (
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
<DetailsList items={items} />
</ScrollablePane>
);
}
ReactDOM.render(
<Fabric className='wrapper'>
<div className='header'>Header</div>
<div className='main'>
<Content />
</div>
<div className='footer'>Footer</div>
</Fabric>,
document.getElementById('content')
);
.wrapper {
display: flex;
flex-direction: column;
width: 100%;
position: absolute;
top: 0;
bottom: 0;
}
.main {
flex: 1;
position: relative;
}
.header, .footer {
background: black;
color: white;
padding: 10px;
}
<script src="//unpkg.com/react@16/umd/react.development.js"></script>
<script src="//unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- could point to local version -->
<script src="//unpkg.com/office-ui-fabric-react/dist/office-ui-fabric-react.min.js"></script>
<div id='content'></div>
[编辑:更新以将问题集中在覆盖问题上;还对 CodePens 进行了编辑] [EDIT2:更新以包含有关 Mohamed Mansour 建议的方法的详细信息]
我在设计 Office UI Fabric React UI 的布局时遇到困难。这是我目前的布局:
目标是将顶部的 CommandBar 和 headers(文本标签和搜索框)固定在顶部,DetailsList 和归档按钮固定在底部并占据尽可能多的空间 space 尽可能在 header 区域之后。
我已成功使用 ScrollablePane 和两个 Sticky 组件将 CommandBar 和按钮固定在所需位置。但是,DetailsList 滚动到包含 CommandBar 和 header 的顶部 Sticky,按钮略微覆盖在 DetailsList 网格的顶部:
我试过使用 Fabric Grid 组件来布置所有部分,但它没有什么不同(如果它有帮助的话)。最好的布局是在两个 Sticky 元素之间放置项目部分;如果将项目部分添加到 Header 或 Footer Sticky 元素中的任何一个,则布局很糟糕。如何确保 DetailsList 不会在顶部和底部组件下方滚动?
这里有两支代码笔可以说明问题:
无网格:https://codepen.io/elegault/pen/aQayvY?editors=0010(文件Header为其元素使用网格,但所有其他元素不在网格中)
const columns = [{
key: 'projectNameColumn',
name: 'Project',
fieldName: 'name',
minWidth: 100,
maxWidth: 200,
isResizable: true,
ariaLabel: 'Operations for Project'
}];
const items = [{
id: '0',
name: 'ABC Construction'
},
{
id: '1',
name: 'Air Bee and Bee'
},
{
id: '2',
name: 'Architectural Salvage'
},
{
id: '3',
name: 'Arkham Airport'
},
{
id: '4',
name: 'Arkham Assembly Hall'
},
{
id: '5',
name: 'Arkham Library'
},
{
id: '6',
name: 'zArkham Renovation'
},
{
id: '7',
name: 'Foo'
},
{
id: '8',
name: 'Foo1'
},
{
id: '9',
name: 'Foo2'
},
{
id: '10',
name: 'Foo3'
},
{
id: '11',
name: 'Foo4'
},
{
id: '12',
name: 'Foo5'
},
{
id: '13',
name: 'Foo6'
},
{
id: '14',
name: 'Foo7'
},
{
id: '15',
name: 'Foo8'
},
{
id: '16',
name: 'Foo9'
},
{
id: '17',
name: 'Foo10'
},
];
class Content extends React.Component {
public render() {
const fileHeader = <
div className = 'ms-Grid' >
<
div className = 'ms-Grid-row' >
<
div className = 'ms-Grid-col ms-sm2 ms-md2 ms-lg2' >
<
img width = '32'
height = '32'
alt = 'logo'
title = 'logo' / >
<
/div> <
div className = 'ms-Grid-col ms-sm10 ms-md10 ms-lg10' >
<
Fabric.Label className = 'ms-font-l ms-fontWeight-bold ms-fontColor-blue' > [TITLE] < /Fabric.Label> <
/div> <
/div> <
div className = 'ms-Grid-row' >
<
div className = 'ms-Grid-col ms-sm2 ms-md2 ms-lg2' >
<
/div> <
div className = 'ms-Grid-col ms-sm10 ms-md10 ms-lg10' >
<
Fabric.Label
className = 'ms-font-m ms-fontWeight-bold ms-fontColor-neutralPrimary' > SELECTED PROJECT: < /Fabric.Label> <
/div> <
/div> <
/div>;
const commandBar = < div >
<
Fabric.CommandBar
isSearchBoxVisible = {
false
}
items = {
[{
key: 'openWebApp',
name: 'Open Web App',
icon: 'OpenInNewWindow', // Or Link
['data-automation-id']: 'openWebAppButton',
title: 'Open web app',
href: 'http://www.codepen.io',
target: '_blank',
}]
}
farItems = {
[{
key: 'menuOptions',
name: 'Options',
icon: 'Settings',
iconOnly: 'true',
['data-automation-id']: 'settingsButton',
subMenuProps: {
items: [{
key: 'privacyPolicy',
name: 'Privacy Policy',
icon: 'PageLock',
href: 'http://www.codepen.io',
target: '_blank',
},
{
key: 'termsOfUse',
name: 'Terms & Conditions',
icon: 'TextDocument',
href: 'http://www.codepen.io',
target: '_blank'
}
]
}
}]
}
/> <
/div>;
const projects = < Fabric.MarqueeSelection selection = {
null
}
data - is - scrollable = {
false
} >
<
Fabric.DetailsList
items = {
items
}
columns = {
columns
}
/> <
/Fabric.MarqueeSelection>;
const selection = < div > [project name] < /div>;
const search = < Fabric.TextField label = 'Search projects:' / > ;
const fileButton = <
div >
<
Fabric.DefaultButton primary = {
true
} > File To Project < /Fabric.DefaultButton> <
/div>;
return ( <
Fabric.Fabric >
<
div style = {
{
height: '500px',
position: 'relative',
maxHeight: 'inherit'
}
} >
<
Fabric.ScrollablePane scrollbarVisibility = {
Fabric.ScrollbarVisibility.auto
} >
<
Fabric.Sticky stickyPosition = {
Fabric.StickyPositionType.Header
} > {
commandBar
} {
fileHeader
} {
selection
} {
search
} <
/Fabric.Sticky> {
projects
} <
Fabric.Sticky stickyPosition = {
Fabric.StickyPositionType.Footer
} > {
fileButton
} <
/Fabric.Sticky> <
/Fabric.ScrollablePane> <
/div> <
/Fabric.Fabric>
);
}
}
ReactDOM.render( <
Content / > ,
document.getElementById('content')
);
完整网格:https://codepen.io/elegault/pen/wQxoRR
const columns = [
{
key: 'projectNameColumn',
name: 'Project',
fieldName: 'name',
minWidth: 100,
maxWidth: 200,
isResizable: true,
ariaLabel: 'Operations for Project'
}
];
const items = [
{id: '0', name: 'ABC Construction'},
{id: '1', name: 'Air Bee and Bee'},
{id: '2', name: 'Architectural Salvage'},
{id: '3', name: 'Arkham Airport'},
{id: '4', name: 'Arkham Assembly Hall'},
{id: '5', name: 'Arkham Library'},
{id: '6', name: 'zArkham Renovation'},
{id: '7', name: 'Foo'},
{id: '8', name: 'Foo1'},
{id: '9', name: 'Foo2'},
{id: '10', name: 'Foo3'},
{id: '11', name: 'Foo4'},
{id: '12', name: 'Foo5'},
{id: '13', name: 'Foo6'},
{id: '14', name: 'Foo7'},
{id: '15', name: 'Foo8'},
{id: '16', name: 'Foo9'},
{id: '17', name: 'Foo10'},
];
class Content extends React.Component {
public render() {
const commandBar = <div>
<Fabric.CommandBar
isSearchBoxVisible={false}
items={[
{
key: 'openWebApp',
name: 'Open Web App',
icon: 'OpenInNewWindow', // Or Link
title: 'Open web app',
href: 'http://www.codepen.io',
target: '_blank',
}
]}
farItems={[
{
key: 'menuOptions',
name: 'Options',
icon: 'Settings',
iconOnly: 'true',
['data-automation-id']: 'settingsButton',
subMenuProps: {
items: [
{
key: 'privacyPolicy',
name: 'Privacy Policy',
icon: 'PageLock',
href: 'http://www.codepen.io',
target: '_blank',
},
{
key: 'termsOfUse',
name: 'Terms & Conditions',
icon: 'TextDocument',
href: 'http://www.codepen.io',
target: '_blank'
}
]
}
}
]}
/>
</div>;
const projects = <Fabric.MarqueeSelection selection={null} data-is-scrollable={false}>
<Fabric.DetailsList
items={items}
columns={columns}
/>
</Fabric.MarqueeSelection>;
const selection = <div>[project name]</div>;
const search = <Fabric.TextField label='Search projects:'/>;
const fileButton =
<div>
<Fabric.DefaultButton primary={true}>File To Project</Fabric.DefaultButton>
</div>;
const fileHeader =
<div className='ms-Grid'>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm2 ms-md2 ms-lg2'>
<img width='32' height='32' alt='logo' title='logo'/>
</div>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
<Fabric.Label className='ms-font-l ms-fontWeight-bold ms-fontColor-blue'>[TITLE]</Fabric.Label>
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm2 ms-md2 ms-lg2'>
</div>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
<Fabric.Label
className='ms-font-m ms-fontWeight-bold ms-fontColor-neutralPrimary'>SELECTED PROJECT:</Fabric.Label>
</div>
</div>
</div>;
return (
<Fabric.Fabric>
<div style={{height:'500px', position:'relative', maxHeight:'inherit'}}>
<Fabric.ScrollablePane scrollbarVisibility={Fabric.ScrollbarVisibility.auto}>
<div className='ms-Grid'>
<Fabric.Sticky stickyPosition={Fabric.StickyPositionType.Header}>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{commandBar}
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{fileHeader}
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{selection}
</div>
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{search}
</div>
</div>
</Fabric.Sticky>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{projects}
</div>
</div>
<Fabric.Sticky stickyPosition={Fabric.StickyPositionType.Footer}>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm10 ms-md10 ms-lg10'>
{fileButton}
</div>
</div>
</Fabric.Sticky>
</div>
</Fabric.ScrollablePane>
</div>
</Fabric.Fabric>
);
}
}
ReactDOM.render(
<Content />,
document.getElementById('content')
);
此外,当尝试在使用嵌套自定义 React 组件的 codepens 之外的项目中使用 Flex 类 或在 parent div 中定义高度(根据 Mohamed Mansour 的建议)时,整个DetailsList 无法呈现。例如,这个 DOM 资源管理器显示了即使设置定义的高度并在多个 'main' div 中使用 flex 仍然无法呈现 DetailsList:
让我们澄清一些术语,这些来自文档:
- ScrollablePane:使用绝对定位,父级必须有相对和高度(来自 flex 或 static)。所以如果你想让它以你自己的方式伸展,你需要满足这些约束。
- Sticky:这些是页眉和页脚的理想选择,但仍将位于滚动条区域内。通常用于多节。
- 重叠内容: 这是完全正常的,你的页眉和页脚没有纯色背景,设置为白色,它会按预期工作。
要实现您想要的效果,让滚动条仅出现在页眉和页脚之间,您可以添加一些正常的 CSS。 运行 看下面的片段。基本上只是一个弹性布局。
我也更新了你的例子:https://codepen.io/mohamedhmansour/pen/rQqqvP
let { DetailsList, Fabric, ScrollablePane, ScrollbarVisibility } = window.Fabric;
function Content() {
const items = [...Array(500).keys()].map(i => ({key: i, text: `Item ${i}`}));
return (
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
<DetailsList items={items} />
</ScrollablePane>
);
}
ReactDOM.render(
<Fabric className='wrapper'>
<div className='header'>Header</div>
<div className='main'>
<Content />
</div>
<div className='footer'>Footer</div>
</Fabric>,
document.getElementById('content')
);
.wrapper {
display: flex;
flex-direction: column;
width: 100%;
position: absolute;
top: 0;
bottom: 0;
}
.main {
flex: 1;
position: relative;
}
.header, .footer {
background: black;
color: white;
padding: 10px;
}
<script src="//unpkg.com/react@16/umd/react.development.js"></script>
<script src="//unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- could point to local version -->
<script src="//unpkg.com/office-ui-fabric-react/dist/office-ui-fabric-react.min.js"></script>
<div id='content'></div>