Due to the default argument promotions when calling variadic functions, float values are implicitly converted to double before the function call, and there is no way to pass a float value to printf. Since there's no way to pass a float value to printf, there's no need for an explicit format specifier for float values.
Having said that, AntoineL brought up an interesting point in a comment that %lf (currently used in scanf to correspond to an argument type double *) may have once stood for "long float", which was a type synonym in pre-C89 days, according to page 42 of the C99 rationale. By that logic, it might make sense that %f was intended to stand for a float value which has been converted to a double.
Regarding the hh and h length modifiers, %hhu and %hu present a well-defined use-case for these format specifiers: You can print the least significant byte of a large unsigned int or unsigned short without a cast, for example:
printf("%hhu\n", UINT_MAX); // This will print (unsigned char)  UINT_MAX
printf("%hu\n",  UINT_MAX); // This will print (unsigned short) UINT_MAX
It isn't particularly well defined what a narrowing conversion from int to char or short will result in, but it is at least implementation-defined, meaning the implementation is required to actually document this decision.
Following the pattern it should have been %hf.
Following the pattern you've observed, %hf should convert values outside of the range of float back to float. However, that kind of narrowing conversion from double to float results in undefined behaviour, and there's no such thing as an unsigned float. The pattern you see doesn't make sense.
To be formally correct, %lf does not denote a long double argument, and if you were to pass a long double argument you would be invoking undefined behaviour. It is explicit from the documentation that:
l (ell)
      ... has no effect on a following a, A, e, E, f, F, g, or G conversion specifier.
I'm surprised nobody else has picked up on this? %lf denotes a double argument, just like %f. If you want to print a long double, use %Lf (capital ell).
It should henceforth make sense that %lf for both printf and scanf correspond to double and double * arguments... %f is exceptional only because of the default argument promotions, for the reasons mentioned earlier.
... and %Ld does not mean long, either. What that means is undefined behaviour.