Question: Using Python and tkinter I have created a dummy app with a scrollable frame. There are two column headings in a container frame. The container frame also contains a canvas. Inside the canvas is an inner frame with two columns of scrollable content. Problem: the column headings do not align with the columns, presumably because the columns in the container frame and the inner frame do not align. But, as far as I can see, I have configured the columns exactly the same way in both frames. Can anyone give me a clue as to what I am overlooking? The code is below. I cannot claim credit for all of the code, as I was following a tutorial from Tutorialspoint (https://www.tutorialspoint.com/implementing-a-scrollbar-using-grid-manager-on-a-tkinter-window), but the tutorial only worked with a single column of scrollable data where the heading scrolled with the data. I changed this so the heading stays put when you scroll and I needed 2 columns of data. N.B. If I uncomment the line starting innerframe.grid(..., the columns match up (almost), but the scrollbar disappears. import tkinter as tk from tkinter import ttk def _on_mousewheel(event): scrollcanvas.yview_scroll(int(-1 * (event.delta / 120)), "units") root=tk.Tk() root.title("Scrollable Grid Example") # Create outer Frame for Grid Layout outerframe = ttk.Frame(root) outerframe.grid(row=0, column=0, columnspan=2, sticky="nsew") # Create a Canvas and Scrollbar scrollcanvas = tk.Canvas(outerframe) scrollbar = ttk.Scrollbar(outerframe, orient="vertical",command=scrollcanvas.yview) scrollcanvas.configure(yscrollcommand=scrollbar.set) # Create label to outer frame/canvas so that it stays put when rows below scroll. label = tk.Label(outerframe, text="Scrollable Buttons", width=20) label.grid(row=0, column=0, pady=5, sticky="w") label1 = tk.Label(outerframe, text="Scrollable Text", width=20) label1.grid(row=0, column=1, pady=5, sticky="w") # Create inner Frame for Scrollable Content innerframe=ttk.Frame(scrollcanvas) # Set binding to adjusts the canvas scroll region when size of the inner frame changes innerframe.bind( "<Configure>", lambda e: scrollcanvas.configure( scrollregion=scrollcanvas.bbox("all") ) ) # Add labels and buttons to the Content Frame for i in range(0, 20): button=ttk.Button(innerframe, text=f"Button {i}", width=20) button.grid(row=i, column=0, pady=5, sticky="w" ) label2 = tk.Label(innerframe, text=f"Text Line {i}", width=20) label2.grid(row=i, column=1, pady=5, sticky="w") # Ensure the window and components expand proportionally when resized. root.rowconfigure(0, weight=1) outerframe.rowconfigure(0, weight=1) innerframe.rowconfigure(0, weight=1) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) outerframe.columnconfigure(0, weight=1) outerframe.columnconfigure(1, weight=1) innerframe.columnconfigure(0, weight=1) innerframe.columnconfigure(1, weight=1) # Place the canvas and scrollbar onto the window, with the scrollbar adjacent to the canvas scrollcanvas.create_window((0, 0), window=innerframe, anchor="nw") scrollcanvas.grid(row=1, column=0, columnspan=2, sticky="nsew") # innerframe.grid(row=1, column=0, columnspan=2, sticky="nw") scrollbar.grid(row=1, column=2, sticky="ns") # Bind the Canvas to Mousewheel Events scrollcanvas.bind_all("<MouseWheel>", _on_mousewheel) # Run the Tkinter Event Loop root.mainloop() def _on_mousewheel(event): scrollcanvas.yview_scroll(int(-1 * (event.delta / 120)), "units") 

Answer: It is because the innerframe does not have the same width of the canvas (which is the sum of the widths of the two labels at the top). You need to:  set highlightthickness=0 in tk.Canvas(...) set the width of innerframe to the same as scrollcanvas (in callback of <Configure> event on scrollcanvas) add uniform=... to outframe.columnconfigure(...) and innerframe.columnconfigure(...) to make sure the two columns inside both outerframe and innerframe have same width  Updated code: import tkinter as tk from tkinter import ttk def _on_mousewheel(event): scrollcanvas.yview_scroll(int(-1 * (event.delta / 120)), "units") root=tk.Tk() root.title("Scrollable Grid Example") # Create outer Frame for Grid Layout outerframe = ttk.Frame(root) outerframe.grid(row=0, column=0, columnspan=2, sticky="nsew") # Create a Canvas and Scrollbar scrollcanvas = tk.Canvas(outerframe, highlightthickness=0) scrollbar = ttk.Scrollbar(outerframe, orient="vertical",command=scrollcanvas.yview) scrollcanvas.configure(yscrollcommand=scrollbar.set) # Create label to outer frame/canvas so that it stays put when rows below scroll. label = tk.Label(outerframe, text="Scrollable Buttons", width=20, bd=1, relief='raised') label.grid(row=0, column=0, pady=5, sticky="w") label1 = tk.Label(outerframe, text="Scrollable Text", width=20, bd=1, relief='raised') label1.grid(row=0, column=1, pady=5, sticky="w") # Create inner Frame for Scrollable Content innerframe=tk.Frame(scrollcanvas, bg='gray80') # Set binding to adjusts the canvas scroll region when size of the inner frame changes innerframe.bind( "<Configure>", lambda e: scrollcanvas.configure( scrollregion=scrollcanvas.bbox("all") ) ) # Add labels and buttons to the Content Frame for i in range(0, 20): button=ttk.Button(innerframe, text=f"Button {i}", width=20) button.grid(row=i, column=0, pady=5, sticky="w" ) label2 = tk.Label(innerframe, text=f"Text Line {i}", width=20, bd=1, relief='solid') label2.grid(row=i, column=1, pady=5, sticky="w") # Ensure the window and components expand proportionally when resized. root.rowconfigure(0, weight=1) outerframe.rowconfigure(0, weight=1) #innerframe.rowconfigure(0, weight=1) # this line is not necessary root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) outerframe.columnconfigure(0, weight=1, uniform=1) # added setting uniform option outerframe.columnconfigure(1, weight=1, uniform=1) innerframe.columnconfigure(0, weight=1, uniform=1) innerframe.columnconfigure(1, weight=1, uniform=1) # Place the canvas and scrollbar onto the window, with the scrollbar adjacent to the canvas scrollcanvas.create_window((0, 0), window=innerframe, anchor="nw", tags=('inner')) # added tags scrollcanvas.grid(row=1, column=0, columnspan=2, sticky="nsew") scrollbar.grid(row=1, column=2, sticky="ns") # Bind the Canvas to Mousewheel Events scrollcanvas.bind_all("<MouseWheel>", _on_mousewheel) # set width of innerframe to same of scrollcanvas scrollcanvas.bind('<Configure>', lambda e: scrollcanvas.itemconfig('inner', width=e.width)) # Run the Tkinter Event Loop root.mainloop()  Note that I have add borders to those labels in order to see the effect easily. Result: