File systems implement some kernel API. So they need to provide functions to open a file by name, to write to a file, to read from a file, and to close a file again (just stick to these basic operations).
The kernel provides functions to read a sector and to write a sector.
The magic in-between is done by the file system "driver". So if a program wants to open a file, the kernel passes that request to the file system driver. The driver then reads the file system meta data and finds the entry for the file. The entry contains file system information, like user and group ownership, permissions, access time and more, and of course information about the sector the file is located on the disk (let's ignore fragmentation here).
So if you take the whole partition and move it to another place on the disk, all stored sector numbers now have an offset, but the file system does not know this offset. So if a program then tries to open a file, the file system will use the sector number as stored in the file system meta data to read the file contents. But as the whole file system is moved several sectors further, the data read will not correspond to the file content and the file is corrupt. Same goes for everything else in the file system as well.
The kernel does not know anything about this. A driver asks to read a sector. The kernel does not know if the sector number should have an offset or not. So this is something that has to be implemented in all file system drivers.
Now imagine a (legacy) file system which uses 16 bits to address sectors. Let's assume a sector is 512 bytes. So the maximum size of the file system can be 32 MiB. If you want to further expand the file system, it has to change the size of an addressable sector from 512 bytes to 1024 bytes. But even now, the file system is full, because all sector numbers are used. So the file system expansion program needs to scan all files, and copy two sectors, which are 1024 bytes in size but only 512 bytes are used, into one sector so that one sector is full (again) and the other one can be freed.
Now imagine this has to be done while the file system is mounted and programs are happily reading and writing from and to the disk. This adds quite some complexity to the file system driver which is only required for this special use case. So it is easier to simply only resize a file system when it is not mounted.
Furthermore, there is more magic under the hood. You can, for example, create a file, open it and remove it. The file does not have a representation in the file system anymore (it has no file name), but as an open descriptor still exists, the file can still be read from and written to. If the program holding the descriptor
forks, even the children can access that file as they inherit the descriptor. As soon as all open descriptors to that file are
closed, the file system will mark the sectors as unused, ready to be used for new files.
So if you
unmount the file system and then
mount it again, those files are gone. And the program is stuck.