Is it ever ok to use bpy.context instead of operator context?
Can I use bpy.context.scene anywhere without issues?

Yes, you can always use it, as the blender scenes are practically never lower than 1. So bpy.context.scene, will always refer to the current scene
But be careful, if for example you do something like assigning this to a variable scene = bpy.context.scene, the scene may at some point, no longer exist, as the user could create new ones, and delete that scene from the bpy.data.scenes

Will bpy.context.selected_objects always return the selected objs in
the 3DView regardless of where the operator was run?

Yes, this always returns the selected objects in a list, so to check for yourself, you can run bpy.context.selected_objects in the Blender console, closing any window with the 3D view, you will notice that it will always refer to the current scene, and consequently to selected objects in the scene.
In addition, by returning a list of objects, you can check if the list contains any objects with if bpy.context.selected_objects
The operator in general already contains the context, in principle if known, within an operator, for example in the function execute(self, context), the context is already present together with self (self is itself, i.e. the operator class).
The context can also be assigned at the beginning of a script, as happens in the Blender console:
C = bpy.context as is also the case with D = bpy.data