There are two widget sets in Tkinter and they are styled in completely different ways. This is the single most confusing thing about the toolkit.
Classic tk widgets take appearance options directly:
import tkinter as tk
tk.Label(root, text="Hello", background="white", foreground="navy",
font=("Helvetica", 14, "bold"), padx=10, pady=6).pack()
Simple, and it works the same everywhere. It also looks nothing like the operating system, which is why ttk exists.
ttk widgets get their appearance from a style, not from options on the widget. Passing background= to a ttk.Label raises an error:
from tkinter import ttk
style = ttk.Style()
style.configure("Title.TLabel", foreground="#3c5a77", font=("Helvetica", 18, "bold"))
ttk.Label(root, text="Hello", style="Title.TLabel").pack()
Style names follow a convention: TLabel, TButton, TEntry, TFrame and so on. Putting a prefix before it, as in Title.TLabel, makes a named variant that inherits everything else from the base.
style.configure("TButton", padding=8)
Configure the base name with no prefix and every button in the application picks it up.
configure sets the normal appearance. map sets what changes when the widget is disabled, active, pressed or focused:
style.map("TButton",
foreground=[("disabled", "#999999"), ("pressed", "white")],
background=[("pressed", "#33608f"), ("active", "#4a7fb5")])
print(style.theme_names())
style.theme_use("clam")
Which themes exist depends on the platform. clam, alt, default and classic are everywhere; Windows and macOS add native ones. clam is the one that responds best to styling, so it is a common choice when you want a consistent look across platforms rather than a native one.
clam is the usual answer when styling appears to do nothing.A few widgets exist only in classic tk: Text, Canvas, Listbox, Menu. Mixing the two sets is normal, but it means a themed application still has to style those four the old way, and matching the colours by hand is part of the job.
style = ttk.Style()
style.theme_use("clam")
style.configure(".", font=("Helvetica", 11))
style.configure("TButton", padding=(12, 6))
style.configure("Heading.TLabel", font=("Helvetica", 16, "bold"))
The dot on its own is the root style: everything inherits from it, so that is where application wide defaults go.