diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt
index c808babeee5d9..faf66afb16f1e 100644
--- a/doc/source/whatsnew/v0.21.0.txt
+++ b/doc/source/whatsnew/v0.21.0.txt
@@ -520,6 +520,7 @@ I/O
- Bug in :func:`read_stata` where the index was not set (:issue:`16342`)
- Bug in :func:`read_html` where import check fails when run in multiple threads (:issue:`16928`)
- Bug in :func:`read_csv` where automatic delimiter detection caused a ``TypeError`` to be thrown when a bad line was encountered rather than the correct error message (:issue:`13374`)
+- Bug in ``DataFrame.to_html()`` with ``notebook=True`` where DataFrames with named indices or non-MultiIndex indices had undesired horizontal or vertical alignment for column or row labels, respectively (:issue:`16792`)
Plotting
^^^^^^^^
diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py
index 6a98497aa1bfe..547b9676717c9 100644
--- a/pandas/io/formats/format.py
+++ b/pandas/io/formats/format.py
@@ -1132,20 +1132,42 @@ def write_tr(self, line, indent=0, indent_delta=4, header=False,
self.write('', indent)
def write_style(self):
- template = dedent("""\
- """)
+ # We use the "scoped" attribute here so that the desired
+ # style properties for the data frame are not then applied
+ # throughout the entire notebook.
+ template_first = """\
+ """
+ template_select = """\
+ .dataframe %s {
+ %s: %s;
+ }"""
+ element_props = [('tbody tr th:only-of-type',
+ 'vertical-align',
+ 'middle'),
+ ('tbody tr th',
+ 'vertical-align',
+ 'top')]
+ if isinstance(self.columns, MultiIndex):
+ element_props.append(('thead tr th',
+ 'text-align',
+ 'left'))
+ if all((self.fmt.has_index_names,
+ self.fmt.index,
+ self.fmt.show_index_names)):
+ element_props.append(('thead tr:last-of-type th',
+ 'text-align',
+ 'right'))
+ else:
+ element_props.append(('thead th',
+ 'text-align',
+ 'right'))
+ template_mid = '\n\n'.join(map(lambda t: template_select % t,
+ element_props))
+ template = dedent('\n'.join((template_first,
+ template_mid,
+ template_last)))
if self.notebook:
self.write(template)
diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py
index 1e174c34221d5..194b5ba3e0276 100644
--- a/pandas/tests/io/formats/test_to_html.py
+++ b/pandas/tests/io/formats/test_to_html.py
@@ -1868,12 +1868,16 @@ def test_to_html_no_index_max_rows(self):
def test_to_html_notebook_has_style(self):
df = pd.DataFrame({"A": [1, 2, 3]})
result = df.to_html(notebook=True)
- assert "thead tr:only-child" in result
+ assert "tbody tr th:only-of-type" in result
+ assert "vertical-align: middle;" in result
+ assert "thead th" in result
def test_to_html_notebook_has_no_style(self):
df = pd.DataFrame({"A": [1, 2, 3]})
result = df.to_html()
- assert "thead tr:only-child" not in result
+ assert "tbody tr th:only-of-type" not in result
+ assert "vertical-align: middle;" not in result
+ assert "thead th" not in result
def test_to_html_with_index_names_false(self):
# gh-16493