diff --git a/src/napari_matplotlib/base.py b/src/napari_matplotlib/base.py
index fda2d2d5..a944d08c 100644
--- a/src/napari_matplotlib/base.py
+++ b/src/napari_matplotlib/base.py
@@ -1,9 +1,10 @@
 import os
+import warnings
 from pathlib import Path
 from typing import List, Optional, Tuple
 
+import matplotlib.style
 import napari
-from matplotlib.axes import Axes
 from matplotlib.backends.backend_qtagg import (
     FigureCanvas,
     NavigationToolbar2QT,
@@ -40,10 +41,8 @@ def __init__(
     ):
         super().__init__(parent=parent)
         self.viewer = napari_viewer
-
+        self.apply_style()
         self.canvas = FigureCanvas()
-
-        self.canvas.figure.patch.set_facecolor("none")
         self.canvas.figure.set_layout_engine("constrained")
         self.toolbar = NapariNavigationToolbar(
             self.canvas, parent=self
@@ -70,28 +69,43 @@ def add_single_axes(self) -> None:
         The Axes is saved on the ``.axes`` attribute for later access.
         """
         self.axes = self.figure.subplots()
-        self.apply_napari_colorscheme(self.axes)
-
-    def apply_napari_colorscheme(self, ax: Axes) -> None:
-        """Apply napari-compatible colorscheme to an Axes."""
-        # get the foreground colours from current theme
-        theme = napari.utils.theme.get_theme(self.viewer.theme, as_dict=False)
-        fg_colour = theme.foreground.as_hex()  # fg is a muted contrast to bg
-        text_colour = theme.text.as_hex()  # text is high contrast to bg
 
-        # changing color of axes background to transparent
-        ax.set_facecolor("none")
-
-        # changing colors of all axes
-        for spine in ax.spines:
-            ax.spines[spine].set_color(fg_colour)
+    def apply_style(self) -> None:
+        """
+        Any user-supplied stylesheet takes highest precidence, otherwise apply
+        the napari-compatible colorscheme (depends on the napari theme).
+        """
+        if self._apply_user_stylesheet_if_present():
+            return
+
+        stylesheet_dir = self._get_path_to_mpl_stylesheets()
+        if self.viewer.theme == "dark":
+            matplotlib.style.use(stylesheet_dir / "napari-dark.mplstyle")
+        elif self.viewer.theme == "light":
+            matplotlib.style.use(stylesheet_dir / "napari-light.mplstyle")
+        else:
+            warnings.warn(
+                f"Napari theme '{self.viewer.theme}' is not supported by"
+                " napari-matplotlib. Will fall back to the matplotlib default."
+            )
+            matplotlib.style.use("default")
+        return
 
-        ax.xaxis.label.set_color(text_colour)
-        ax.yaxis.label.set_color(text_colour)
+    def _apply_user_stylesheet_if_present(self) -> bool:
+        """
+        Apply the user-supplied stylesheet if present.
 
-        # changing colors of axes labels
-        ax.tick_params(axis="x", colors=text_colour)
-        ax.tick_params(axis="y", colors=text_colour)
+        Returns
+        -------
+            True if the stylesheet was present and applied.
+            False otherwise.
+        """
+        if (Path.cwd() / "user.mplstyle").exists():
+            matplotlib.style.use("./user.mplstyle")
+            return True
+            # TODO: can put more complicated stuff in here. Like a config dir,
+            # or take a given named file from the matplotlib user styles
+        return False
 
     def _on_theme_change(self) -> None:
         """Update MPL toolbar and axis styling when `napari.Viewer.theme` is changed.
@@ -100,8 +114,8 @@ def _on_theme_change(self) -> None:
             At the moment we only handle the default 'light' and 'dark' napari themes.
         """
         self._replace_toolbar_icons()
-        if self.figure.gca():
-            self.apply_napari_colorscheme(self.figure.gca())
+        self.apply_style()
+        # self.canvas.reload()
 
     def _theme_has_light_bg(self) -> bool:
         """
@@ -116,6 +130,9 @@ def _theme_has_light_bg(self) -> bool:
         _, _, bg_lightness = theme.background.as_hsl_tuple()
         return bg_lightness > 0.5
 
+    def _get_path_to_mpl_stylesheets(self) -> Path:
+        return Path(__file__).parent / "stylesheets"
+
     def _get_path_to_icon(self) -> Path:
         """
         Get the icons directory (which is theme-dependent).
@@ -245,7 +262,7 @@ def _draw(self) -> None:
             isinstance(layer, self.input_layer_types) for layer in self.layers
         ):
             self.draw()
-        self.apply_napari_colorscheme(self.figure.gca())
+        self.apply_style()
         self.canvas.draw()
 
     def clear(self) -> None:
diff --git a/src/napari_matplotlib/stylesheets/napari-dark.mplstyle b/src/napari_matplotlib/stylesheets/napari-dark.mplstyle
new file mode 100644
index 00000000..1658f9b4
--- /dev/null
+++ b/src/napari_matplotlib/stylesheets/napari-dark.mplstyle
@@ -0,0 +1,12 @@
+# Dark-theme napari colour scheme for matplotlib plots
+
+# text (very light grey - almost white): #f0f1f2
+# foreground (mid grey):                 #414851
+# background (dark blue-gray):           #262930
+
+figure.facecolor    : none
+axes.labelcolor     : f0f1f2
+axes.facecolor      : none
+axes.edgecolor      : 414851
+xtick.color         : f0f1f2
+ytick.color         : f0f1f2
diff --git a/src/napari_matplotlib/stylesheets/napari-light.mplstyle b/src/napari_matplotlib/stylesheets/napari-light.mplstyle
new file mode 100644
index 00000000..be78f2ce
--- /dev/null
+++ b/src/napari_matplotlib/stylesheets/napari-light.mplstyle
@@ -0,0 +1,12 @@
+# Light-theme napari colour scheme for matplotlib plots
+
+# text ():       #3b3a39
+# foreground (): #d6d0ce
+# background (): #efebe9
+
+figure.facecolor    : none
+axes.labelcolor     : 3b3a39
+axes.facecolor      : none
+axes.edgecolor      : d6d0ce
+xtick.color         : 3b3a39
+ytick.color         : 3b3a39
diff --git a/src/napari_matplotlib/tests/baseline/test_histogram_2D.png b/src/napari_matplotlib/tests/baseline/test_histogram_2D.png
index b76d1e10..aeb4fb02 100644
Binary files a/src/napari_matplotlib/tests/baseline/test_histogram_2D.png and b/src/napari_matplotlib/tests/baseline/test_histogram_2D.png differ
diff --git a/src/napari_matplotlib/tests/baseline/test_histogram_3D.png b/src/napari_matplotlib/tests/baseline/test_histogram_3D.png
index 2dffdcb2..3e6abfb6 100644
Binary files a/src/napari_matplotlib/tests/baseline/test_histogram_3D.png and b/src/napari_matplotlib/tests/baseline/test_histogram_3D.png differ
diff --git a/src/napari_matplotlib/tests/test_theme.py b/src/napari_matplotlib/tests/test_theme.py
index dfeb5b5f..129a79ba 100644
--- a/src/napari_matplotlib/tests/test_theme.py
+++ b/src/napari_matplotlib/tests/test_theme.py
@@ -1,8 +1,13 @@
+import shutil
+from pathlib import Path
+
+import matplotlib
 import napari
 import numpy as np
 import pytest
+from matplotlib.colors import to_rgba
 
-from napari_matplotlib import ScatterWidget
+from napari_matplotlib import HistogramWidget, ScatterWidget
 from napari_matplotlib.base import NapariMPLWidget
 
 
@@ -49,8 +54,23 @@ def test_theme_background_check(make_napari_viewer):
     assert widget._theme_has_light_bg() is True
 
     _mock_up_theme()
+    with pytest.warns(UserWarning, match="theme 'blue' is not supported"):
+        viewer.theme = "blue"
+        assert widget._theme_has_light_bg() is True
+
+
+def test_unknown_theme_raises_warning(make_napari_viewer):
+    """
+    Check that widget construction warns if it doesn't recognise napari's theme.
+
+    Note that testing for the expected warning when theme is changed _after_ the
+    widget is created is part of ``test_theme_background_check``.
+    """
+    viewer = make_napari_viewer()
+    _mock_up_theme()  # creates the 'blue' theme which is not a standard napari theme
     viewer.theme = "blue"
-    assert widget._theme_has_light_bg() is True
+    with pytest.warns(UserWarning, match="theme 'blue' is not supported"):
+        HistogramWidget(viewer)
 
 
 @pytest.mark.parametrize(
@@ -88,3 +108,34 @@ def test_titles_respect_theme(
 
     assert ax.xaxis.label.get_color() == expected_text_colour
     assert ax.yaxis.label.get_color() == expected_text_colour
+
+
+def find_mpl_stylesheet(name: str) -> Path:
+    """Find the built-in matplotlib stylesheet."""
+    return Path(matplotlib.__path__[0]) / f"mpl-data/stylelib/{name}.mplstyle"
+
+
+def test_stylesheet_in_cwd(tmpdir, make_napari_viewer, image_data):
+    """
+    Test that a stylesheet in the current directory is given precidence.
+
+    Do this by copying over a stylesheet from matplotlib's built in styles,
+    naming it correctly, and checking the colours are as expected.
+    """
+    with tmpdir.as_cwd():
+        # Copy Solarize_Light2 to current dir as if it was a user-overriden stylesheet.
+        shutil.copy(find_mpl_stylesheet("Solarize_Light2"), "./user.mplstyle")
+        viewer = make_napari_viewer()
+        viewer.add_image(image_data[0], **image_data[1])
+        widget = HistogramWidget(viewer)
+        ax = widget.figure.gca()
+
+        # The axes should have a light brownish grey background:
+        assert ax.get_facecolor() == to_rgba("#eee8d5")
+        assert ax.patch.get_facecolor() == to_rgba("#eee8d5")
+
+        # The figure background and axis gridlines are light yellow:
+        assert widget.figure.patch.get_facecolor() == to_rgba("#fdf6e3")
+        for gridline in ax.get_xgridlines() + ax.get_ygridlines():
+            assert gridline.get_visible() is True
+            assert gridline.get_color() == "#fdf6e3"