Use $List[0].VideoHeight, not $List.VideoHeight[0].
After all, from a conceptual standpoint, you want to get the .VideoHeight value of the first list item ($List[0]), not the first element of the whole list's video-height values ($List.VideoHeight).[1]
The reason it works with multiple items in $List is that PowerShell's member-access enumeration then returns an array of .VideoHeight property values, where indexing with [0] works as expected.
The reason it doesn't work as expected with a single item in $List is that then only a scalar (single) .VideoHeight property value is returned, and that scalar is of type [string]. Indexing into a single string returns the individual characters in the string, which is what you saw.
Simple demonstration:
PS> ([pscustomobject] @{ VideoHeight = '1080' }).VideoHeight[0]
1 # [char] '1', the first character in string '1080'
vs.
PS> ([pscustomobject] @{ VideoHeight = '1080' },
[pscustomobject] @{ VideoHeight = '1081' }).VideoHeight[0]
1080 # [string] '1080', the first element in array '1080', '1081'
So there are two factors contributing to the unexpected behavior:
PowerShell's member-access enumeration applies the same logic as when pipeline output is collected: If the collection whose members are being enumerated happens to have just one element, that member (property) value is returned as-is; only 2 or more elements result in an [object[]] array of values.
- It is somewhat unfortunate that member-access enumeration behaves this way; the behavior can be even more surprising when the property values are arrays themselves: the resulting arrays are then concatenated instead of becoming individual subarrays in the output array - see this GitHub issue.
The standard behavior of the .NET System.String type ([string]), which allows direct indexing of the characters that make up the string (e.g. "foo"[0] yielding [char] 'f').
Strictly speaking, it is whatever language consumes the type that implements the [...] indexer syntax, which is a form of syntactic sugar; the underlying type only has a parameterized property named Chars, which both C# and PowerShell expose more conveniently via [...].
In the case of [string], however, this unfortunately conflicts with PowerShell's unified handling of collections and scalars, where usually $scalar[0] is the same as $scalar - see this answer for background information.
[1] If collecting the values of all $List .VideoHeight property values consistently returned an array (why it doesn't is explained in the second section), the two statements would be functionally equivalent, though $List[0].VideoHeight is still preferable for efficiency (no intermediate array of property values must be constructed) and also for the sake of avoiding potential member-name conflicts, which member-access enumeration inherently entails - see this GitHub issue.