Scaling ScrollingFrames’ CanvasSizes with LocalScripts

Hello everyone!

I’ve seen many people (and games) having trouble with having ScrollingFrame’s elements not being visible because the frame doesn’t go down all the way or maybe it goes down too far.

Well there may be many solutions, but I’ll be explaining the one I use all the time. It may not make sense at first like it did to me but you’ll get used to it and will be happy with the result. The reason I say it may not make sense is because you should use offset instead of scale when setting the CanvasSize. Note that I’m only referring to the CanvasSize; dont use Offset for Size, Position, etc…

Wait, why not use AutomaticCanvasSize? I don’t recommend that you use AutomaticCanvasSize because it dynamically scales the elements so it fits the scrollingFrame’s size. However my way that I’ll explain makes it so the CanvasSize of the scrollingFrame dynamically adjusts which is quite the opposite of using AutomaticCanvasSize.

I’ll go step-by-step and then link the file for the example place I’m showing below.

STEPS:

  1. Make sure you have a your Gui ready and then insert a ScrollingFrame
Images

Screenshot 2025-02-24 at 4.35.06 PM

  1. I suggest that you set the Anchor Point to (0.5, 0.5) and Position and Size to a scale value. As. you can see, I have many other elements like AspectRatios, I suggest using these anywhere in your developmental UI to make it consistent.

  2. Here, the real work beings:

  • Add a Gui formatter to your ScrollingFrame (ie. UIListLayout, UITableLayout, UIGridLayout, UIPageLayout). Do note that this is an important step in making it possible to use offset as a size.

  • Set the AutomaticCanvasSize to Y or X depending on the desired scroll direction of the ScrollingFrame. Also set the CanvasSize property of the scrollingFrame to {0, 0, 0, 0}

  • Insert a LocalScript into your game somewhere that is acceptable. I prefer to have a Folder named ‘Gui’ in StarterPlayerScripts. Then name your LocalScript as this will keep your game organized.

Example

Screenshot 2025-02-24 at 4.43.11 PM

Okay, let’s start coding. I will provide 2 scripts that are slightly different depending on the ScrollingDirection. Then I will explain how the script operates in general.

Make sure to read the comments; they may be really far off to the right.

Y scrollingFrame Code

--This is for a scrollingFrame in the Y direction.

--// INITALIZE GUI VARIABLES \\--
local player = game:GetService("Players").LocalPlayer
local exampleGui = player.PlayerGui:WaitForChild("ExampleGui")
local container = exampleGui.Container
local scrollingFrame = container.ScrollingFrame -- Set equal to your scrollingFrame
local UIListLayout = scrollingFrame.UIListLayout -- Should be a child of your scrollingFrame

--// INITALIZE WORKSPACE VARIABLES \\--
local currentCamera = game:GetService("Workspace").CurrentCamera

local function updateCanvasSizeBasedOnAbsoluteContentSize()
	local viewportYSize = currentCamera.ViewportSize.Y -- This is an offest value, not an Udim2 value. Will return the Y size of the screen in pixels.
	local offset = viewportYSize * 0.025 -- It's sometimes a good idea to have an offset so there is some wiggle room/gap near the ends of the scrollingFrame even if you have a UIPadding element.
	
	local AbsoluteContentSize_Y = UIListLayout.AbsoluteContentSize.Y -- Will get the amount of pixels on the y-axis that the items within the scrollingFrame takes up.
	
	-- Set the CanvasSize of the scrollingFrame
	scrollingFrame.CanvasSize = UDim2.fromOffset(0, AbsoluteContentSize_Y + offset)
end

updateCanvasSizeBasedOnAbsoluteContentSize() -- It's a good idea to initalize the size of the Canvas at the start of the session.

-- Now we will need to change the CanvasSize if the amount of items within the scrollingFrame changes or when the size of the user's window changes (like if they resize the game's window on PC).

currentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(updateCanvasSizeBasedOnAbsoluteContentSize)

UIListLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(updateCanvasSizeBasedOnAbsoluteContentSize)

X scrollingFrame Code:


--This is for a scrollingFrame in the X direction.

--// INITALIZE GUI VARIABLES \\--
local player = game:GetService("Players").LocalPlayer
local exampleGui = player.PlayerGui:WaitForChild("ExampleGui")
local container = exampleGui.Container
local scrollingFrame = container.ScrollingFrame -- Set equal to your scrollingFrame
local UIListLayout = scrollingFrame.UIListLayout -- Should be a child of your scrollingFrame

--// INITALIZE WORKSPACE VARIABLES \\--
local currentCamera = game:GetService("Workspace").CurrentCamera

local function updateCanvasSizeBasedOnAbsoluteContentSize()
	local viewportXSize = currentCamera.ViewportSize.X -- This is an offest value, not an Udim2 value. Will return the X size of the screen in pixels.
	local offset = viewportXSize * 0.025 -- It's sometimes a good idea to have an offset so there is some wiggle room/gap near the ends of the scrollingFrame even if you have a UIPadding element.
	
	local AbsoluteContentSize_X = UIListLayout.AbsoluteContentSize.X -- Will get the amount of pixels on the x-axis that the items within the scrollingFrame takes up.
	
	-- Set the CanvasSize of the scrollingFrame
	scrollingFrame.CanvasSize = UDim2.fromOffset(AbsoluteContentSize_X + offset, 0)
end

updateCanvasSizeBasedOnAbsoluteContentSize() -- It's a good idea to initalize the size of the Canvas at the start of the session.

-- Now we will need to change the CanvasSize if the amount of items within the scrollingFrame changes or when the size of the user's window changes (like if they resize the game's window on PC).

currentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(updateCanvasSizeBasedOnAbsoluteContentSize)

UIListLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(updateCanvasSizeBasedOnAbsoluteContentSize)

Why this works:

  1. Scale is based on the parent UI element’s size, which makes it unpredictable for dynamic content inside a scrollingFrame. Whereas Offset uses exact pixel values, ensuring that the CanvasSize expands properly based on the content inside the scrollingFrame.

Okay, let’s test it out. I’m going to add some UI elements to my scrollingFrame and see how they work. Remember to only use offset for the CanvasSize, every other thing should be using Scale like Position and Size (in my opinion).

Images


Video (720p because file limit)

Here is the file for the place shown in the images/video.
ScrollingFrameExample.rbxl (71.6 KB)

Hopes this helps you with your journey in creating epic Roblox games!
7eoeb

2 Likes

hmm I skimmed through this but I think the error was just the popular scaling plugin was erroring? try manually converting it so your frames can be scaled in the scrolling frame.

At first, setting the AutomaticCanvasSize and setting the canvas size to 0, 0, 0, 0 seemed to work fine enough, but i have experienced issues with it, so i hope this method can resolve those, thanks for the tutorial :+1:

1 Like

Although I like this, It feels like a workaround. The documentation really isnt specific enough on what “CanvasSize” is used to calculate. It’d be much simpler if there a formula that could be used to actually convert it with scale. Is there anywhere that describes how the value is used more extensively than the api?