diff --git a/__tests__/src/components/OpenSeadragonViewer.test.js b/__tests__/src/components/OpenSeadragonViewer.test.js
index 8113ca8e9bfbda73b9526d85e757ff14710bd62f..de9d67affb259637b40c27ae79ad0759fe08b588 100644
--- a/__tests__/src/components/OpenSeadragonViewer.test.js
+++ b/__tests__/src/components/OpenSeadragonViewer.test.js
@@ -4,7 +4,6 @@ import OpenSeadragon from 'openseadragon';
 import { OpenSeadragonViewer } from '../../../src/components/OpenSeadragonViewer';
 import OpenSeadragonCanvasOverlay from '../../../src/lib/OpenSeadragonCanvasOverlay';
 import Annotation from '../../../src/lib/Annotation';
-import ZoomControls from '../../../src/containers/ZoomControls';
 
 jest.mock('openseadragon');
 jest.mock('../../../src/lib/OpenSeadragonCanvasOverlay');
@@ -26,6 +25,7 @@ describe('OpenSeadragonViewer', () => {
         config={{}}
         updateViewport={updateViewport}
         t={k => k}
+        classes={{ controls: 'controls' }}
       >
         <div className="foo" />
       </OpenSeadragonViewer>,
@@ -37,8 +37,8 @@ describe('OpenSeadragonViewer', () => {
   it('renders child components', () => {
     expect(wrapper.find('.foo').length).toBe(1);
   });
-  it('renders ZoomControls', () => {
-    expect(wrapper.find(ZoomControls).length).toBe(1);
+  it('renders viewer controls', () => {
+    expect(wrapper.find('.controls').length).toBe(1);
   });
   describe('tileSourcesMatch', () => {
     it('when they do not match', () => {
diff --git a/__tests__/src/components/WindowViewer.test.js b/__tests__/src/components/WindowViewer.test.js
index ab419d68a6bbcbdc15faf2477f290b12901f8abf..f3b21fc8939a39e238cce283f33beac1157fce03 100644
--- a/__tests__/src/components/WindowViewer.test.js
+++ b/__tests__/src/components/WindowViewer.test.js
@@ -1,9 +1,11 @@
 import React from 'react';
 import { shallow } from 'enzyme';
 import manifesto from 'manifesto.js';
+import Typography from '@material-ui/core/Typography';
 import { WindowViewer } from '../../../src/components/WindowViewer';
 import OSDViewer from '../../../src/containers/OpenSeadragonViewer';
 import ViewerNavigation from '../../../src/containers/ViewerNavigation';
+import ZoomControls from '../../../src/containers/ZoomControls';
 import fixture from '../../fixtures/version-2/019.json';
 import emptyCanvasFixture from '../../fixtures/version-2/emptyCanvas.json';
 import otherContentFixture from '../../fixtures/version-2/299843.json';
@@ -22,6 +24,7 @@ let mockWindow = {
 function createWrapper(props) {
   return shallow(
     <WindowViewer
+      canvasLabel="label"
       infoResponses={{}}
       fetchInfoResponse={() => {}}
       fetchAnnotation={() => {}}
@@ -41,7 +44,11 @@ describe('WindowViewer', () => {
     expect(wrapper.matchesElement(
       <>
         <OSDViewer>
-          <ViewerNavigation />
+          <div>
+            <ZoomControls />
+            <ViewerNavigation />
+            <Typography>label</Typography>
+          </div>
         </OSDViewer>
       </>,
     )).toBe(true);
diff --git a/__tests__/src/components/ZoomControls.test.js b/__tests__/src/components/ZoomControls.test.js
index f76ce271def4ebff8b63e391ea890699f617882a..31f5fb083c92096bc7892b4aea878f6eab232edd 100644
--- a/__tests__/src/components/ZoomControls.test.js
+++ b/__tests__/src/components/ZoomControls.test.js
@@ -12,7 +12,7 @@ describe('ZoomControls', () => {
     updateViewport = jest.fn();
     wrapper = shallow(
       <ZoomControls
-        classes={{}}
+        classes={{ zoom_controls: 'zoom_controls' }}
         windowId="xyz"
         viewer={viewer}
         showZoomControls={showZoomControls}
@@ -23,7 +23,7 @@ describe('ZoomControls', () => {
 
   describe('with showZoomControls=false', () => {
     it('renders nothing unless asked', () => {
-      expect(wrapper.find('WithStyles(List)').length).toBe(0);
+      expect(wrapper.find('div.zoom_controls').length).toBe(0);
     });
   });
 
@@ -33,7 +33,7 @@ describe('ZoomControls', () => {
       updateViewport = jest.fn();
       wrapper = shallow(
         <ZoomControls
-          classes={{}}
+          classes={{ zoom_controls: 'zoom_controls' }}
           windowId="xyz"
           viewer={viewer}
           showZoomControls
@@ -43,7 +43,7 @@ describe('ZoomControls', () => {
     });
 
     it('renders a couple buttons', () => {
-      expect(wrapper.find('WithStyles(List)').length).toBe(1);
+      expect(wrapper.find('div.zoom_controls').length).toBe(1);
     });
 
     it('has a zoom-in button', () => {
diff --git a/src/components/OpenSeadragonViewer.js b/src/components/OpenSeadragonViewer.js
index 50708b5ac3df3f776f1e861e68fa4e0498b30ca0..62b592661514883efc90c71a8d058edc21d6f98a 100644
--- a/src/components/OpenSeadragonViewer.js
+++ b/src/components/OpenSeadragonViewer.js
@@ -1,8 +1,8 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
+import Paper from '@material-ui/core/Paper';
 import OpenSeadragon from 'openseadragon';
 import ns from '../config/css-ns';
-import ZoomControls from '../containers/ZoomControls';
 import OpenSeadragonCanvasOverlay from '../lib/OpenSeadragonCanvasOverlay';
 
 /**
@@ -259,7 +259,7 @@ export class OpenSeadragonViewer extends Component {
    */
   render() {
     const {
-      windowId, children, label, t,
+      windowId, children, classes, label, t,
     } = this.props;
 
     return (
@@ -270,8 +270,9 @@ export class OpenSeadragonViewer extends Component {
           ref={this.ref}
           aria-label={t('item', { label })}
         >
-          <ZoomControls windowId={windowId} />
-          { children }
+          <Paper square className={classes.controls} elevation={0}>
+            { children }
+          </Paper>
         </section>
       </>
     );
@@ -284,6 +285,7 @@ OpenSeadragonViewer.defaultProps = {
   tileSources: [],
   viewer: null,
   label: null,
+  classes: {},
 };
 
 OpenSeadragonViewer.propTypes = {
@@ -295,4 +297,5 @@ OpenSeadragonViewer.propTypes = {
   windowId: PropTypes.string.isRequired,
   label: PropTypes.string,
   t: PropTypes.func.isRequired,
+  classes: PropTypes.object, // eslint-disable-line react/forbid-prop-types
 };
diff --git a/src/components/WindowViewer.js b/src/components/WindowViewer.js
index 78b5354560789a897ae934acd703cdb380deb9db..5fa7b8176a4576d8dabd903e5b5ead7d1f3cc8ea 100644
--- a/src/components/WindowViewer.js
+++ b/src/components/WindowViewer.js
@@ -1,9 +1,12 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
+import Typography from '@material-ui/core/Typography';
 import OSDViewer from '../containers/OpenSeadragonViewer';
+import ZoomControls from '../containers/ZoomControls';
 import ViewerNavigation from '../containers/ViewerNavigation';
 import ManifestoCanvas from '../lib/ManifestoCanvas';
 import CanvasGroupings from '../lib/CanvasGroupings';
+import ns from '../config/css-ns';
 
 /**
  * Represents a WindowViewer in the mirador workspace. Responsible for mounting
@@ -121,7 +124,7 @@ export class WindowViewer extends Component {
    * Renders things
    */
   render() {
-    const { window } = this.props;
+    const { canvasLabel, window } = this.props;
     return (
       <>
         <OSDViewer
@@ -129,7 +132,15 @@ export class WindowViewer extends Component {
           currentCanvases={this.currentCanvases()}
           windowId={window.id}
         >
-          <ViewerNavigation window={window} canvases={this.canvases} />
+          <div className={ns('canvas-nav')}>
+            <ZoomControls windowId={window.id} />
+            <ViewerNavigation window={window} canvases={this.canvases} />
+            {
+              canvasLabel && (
+                <Typography variant="caption" className={ns('canvas-label')}>{canvasLabel}</Typography>
+              )
+            }
+          </div>
         </OSDViewer>
       </>
     );
@@ -142,4 +153,9 @@ WindowViewer.propTypes = {
   fetchInfoResponse: PropTypes.func.isRequired,
   manifest: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
   window: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
+  canvasLabel: PropTypes.string,
+};
+
+WindowViewer.defaultProps = {
+  canvasLabel: undefined,
 };
diff --git a/src/components/ZoomControls.js b/src/components/ZoomControls.js
index bd29e210cf87c5592c8e7c3409ab20c1021b98c0..718a9ec9fd9cd2a7eed4e084dee4908b7cee7848 100644
--- a/src/components/ZoomControls.js
+++ b/src/components/ZoomControls.js
@@ -1,7 +1,5 @@
 import React, { Component } from 'react';
 import IconButton from '@material-ui/core/IconButton';
-import List from '@material-ui/core/List';
-import ListItem from '@material-ui/core/ListItem';
 import AddCircleIcon from '@material-ui/icons/AddCircleOutlineSharp';
 import RemoveCircleIcon from '@material-ui/icons/RemoveCircleOutlineSharp';
 import PropTypes from 'prop-types';
@@ -73,23 +71,17 @@ export class ZoomControls extends Component {
       );
     }
     return (
-      <List className={classes.zoom_controls}>
-        <ListItem>
-          <IconButton aria-label={t('zoomIn')} onClick={this.handleZoomInClick}>
-            <AddCircleIcon />
-          </IconButton>
-        </ListItem>
-        <ListItem>
-          <IconButton aria-label={t('zoomOut')} onClick={this.handleZoomOutClick}>
-            <RemoveCircleIcon />
-          </IconButton>
-        </ListItem>
-        <ListItem>
-          <IconButton aria-label={t('zoomReset')} onClick={this.handleZoomResetClick}>
-            <RestoreZoomIcon />
-          </IconButton>
-        </ListItem>
-      </List>
+      <div className={classes.zoom_controls}>
+        <IconButton aria-label={t('zoomIn')} onClick={this.handleZoomInClick}>
+          <AddCircleIcon />
+        </IconButton>
+        <IconButton aria-label={t('zoomOut')} onClick={this.handleZoomOutClick}>
+          <RemoveCircleIcon />
+        </IconButton>
+        <IconButton aria-label={t('zoomReset')} onClick={this.handleZoomResetClick}>
+          <RestoreZoomIcon />
+        </IconButton>
+      </div>
     );
   }
 }
diff --git a/src/config/settings.js b/src/config/settings.js
index ed89c75786110fe207e62b4102363e87899f361d..6f49d0842a7d06f1aa3557af07d98febf7065c1e 100644
--- a/src/config/settings.js
+++ b/src/config/settings.js
@@ -40,7 +40,7 @@ export default {
       },
       caption: {
         fontSize: "0.772rem",
-        letterSpacing: "0.33em",
+        letterSpacing: "0.033em",
         lineHeight: "1.6rem",
       },
       body1Next: {
diff --git a/src/containers/OpenSeadragonViewer.js b/src/containers/OpenSeadragonViewer.js
index 7099f30dc6460276366607398747635cf8499a66..4e12d11f0ade0b2430f2f84083aa57b43a8914a0 100644
--- a/src/containers/OpenSeadragonViewer.js
+++ b/src/containers/OpenSeadragonViewer.js
@@ -1,6 +1,8 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
+import { withStyles } from '@material-ui/core';
+import { fade } from '@material-ui/core/styles/colorManipulator';
 import miradorWithPlugins from '../lib/miradorWithPlugins';
 import { OpenSeadragonViewer } from '../components/OpenSeadragonViewer';
 import * as actions from '../state/actions';
@@ -38,7 +40,23 @@ const mapDispatchToProps = {
   updateViewport: actions.updateViewport,
 };
 
+/**
+ *
+ * @param theme
+ * @returns {{windowSideBarHeading: *}}
+ */
+const styles = theme => ({
+  controls: {
+    width: '100%',
+    position: 'absolute',
+    bottom: 0,
+    zIndex: 50,
+    backgroundColor: fade(theme.palette.background.paper, 0.5),
+  },
+});
+
 const enhance = compose(
+  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, mapDispatchToProps),
   miradorWithPlugins,
diff --git a/src/containers/WindowViewer.js b/src/containers/WindowViewer.js
index 85cf2a36df5a8f8d2f5894b8fbcde973f58433b3..5c8b47026bcd2843fa948740a7d168c76e662a0a 100644
--- a/src/containers/WindowViewer.js
+++ b/src/containers/WindowViewer.js
@@ -2,6 +2,10 @@ import { compose } from 'redux';
 import { connect } from 'react-redux';
 import * as actions from '../state/actions';
 import miradorWithPlugins from '../lib/miradorWithPlugins';
+import {
+  getCanvasLabel,
+  getSelectedCanvas,
+} from '../state/selectors';
 import { WindowViewer } from '../components/WindowViewer';
 
 /**
@@ -9,8 +13,12 @@ import { WindowViewer } from '../components/WindowViewer';
  * @memberof WindowViewer
  * @private
  */
-const mapStateToProps = state => (
+const mapStateToProps = (state, { window }) => (
   {
+    canvasLabel: getCanvasLabel(
+      getSelectedCanvas(state, window.id),
+      state.windows[window.id].canvasIndex,
+    ),
     infoResponses: state.infoResponses,
   }
 );
diff --git a/src/containers/ZoomControls.js b/src/containers/ZoomControls.js
index 2f468c4354379592b700fe2a77d50963ff69668f..d333253896b3341dc60d5dd9275aec966d4f3411 100644
--- a/src/containers/ZoomControls.js
+++ b/src/containers/ZoomControls.js
@@ -32,10 +32,8 @@ const mapDispatchToProps = { updateViewport: actions.updateViewport };
  */
 const styles = theme => ({
   zoom_controls: {
-    position: 'absolute',
-    right: 0,
-    zIndex: 33,
-    top: 0,
+    display: 'flex',
+    flexDirection: 'row',
   },
   ListItem: {
     paddingTop: 0,
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 0022f7500612ed8428ebc76b7a240419f41ce0b1..8ff74cc5528efa470072c704a48bf781aa9cf16e 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -99,13 +99,25 @@
     position: relative;
   }
 
-  &-osd-navigation {
-    bottom: 10px;
-    left: 0;
+  div + &-osd-navigation:before {
+    content: '|';
+    color: $gray;
     position: absolute;
-    right: 0;
+    font-size: 24px;
+    top: 12px;
+  }
+
+  &-canvas-nav {
+    display: flex;
+    justify-content: center;
+    flex-wrap: wrap;
     text-align: center;
-    z-index: 33;
+  }
+
+  &-canvas-label {
+    width: 100%;
+    text-overflow: ellipsis;
+    padding-bottom: 3px;
   }
 
   &-thumb-navigation {