How to add a stylesheet to a page after the layout has already been built?

The normal way to add a stylesheet to a page is to call \Magento\Framework\View\Page\Config::addPageAsset()
Here is an example: How to load JavaScript or stylesheet conditionally depends on backend config settings?

But sometimes the normal way is not available because the layout has already been built (the \Magento\Framework\View\Layout\Builder::build() has already been finished).
I have found 2 solutions of the problem.

Solution 1

If the layout is already built but HTML document is not rendered yet then we can generate <link> tag manually and insert it to the HTML document.
A <link> tag is valid inside the <body> tag in HTML 5.

We can use the \Magento\Framework\View\Asset\File::getUrl() method to get an asset url:

 * @param string $asset
 * @return string
function getAssetUrl($asset) {
	/** @var \Magento\Framework\ObjectManagerInterface $om */
	$om = \Magento\Framework\App\ObjectManager::getInstance();
	/** @var \Magento\Framework\View\Asset\Repository $assetRepository */
	$assetRepository = $om->get('Magento\Framework\View\Asset\Repository');
	return $assetRepository->createAsset($asset)->getUrl();

For example:


Solution 2

If the decision whether to load the asset need to be made interactively on the browser side then we can get the asset url using the Solution 1 and then pass the asset url to a JavaScript component as a parameter.
Then the JavaScript component can generate a <link> tag interactively to load the asset:

var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = url;

It is not a simple way but it works. Waiting for a standard and more simplier way:

See also: