How to use position absolute in apache-fo

2019-05-30 10:32发布

问题:

I am having problem in apache-fo, In General HTML & CSS if we give position:absolute to a div, it will take from its parent Top and Left, But Same thing if I give position: absolute to a particular block container in Apache FO, it taking from the Page Top & Left.

For Example:

<fo:flow flow-name="xsl-region-body">

[I want this type of scenario][1]
<fo:block-container width="100%" color="rgb(0, 0, 0)">
<fo:block>

<fo:block-container>
<fo:block-container width="50%" left="1in" top="1in" position="absolute"><fo:block>First Block</fo:block></fo:block-container>
<fo:block-container width="50%" left="2in" top="3in" position="absolute"><fo:block>Second Block</fo:block></fo:block-container>
</fo:block-container>

<fo:block-container>

<fo:block-container width="50%" left="1in" top="1in" position="absolute"><fo:block>Third Block</fo:block></fo:block-container>
<fo:block-container width="50%" left="2in" top="2in" position="absolute"><fo:block>Fourth Block</fo:block></fo:block-container>
</fo:block-container>

</fo:block>
</fo:block-container>

</fo:flow>

In Given Example: I am giving postion absolute to block container and top 1in; and left 1in; Instead of taking 1in from top & left from their parent, It taking 1in from top & left from top block Container.

I want output like After First Block, Second Block will display after 1in from Top & 1in from Left of First Block. But now it showing all the First Block, Second Block, Third Block, Fourth Block are coming in the Same position, and taking Top & Left 1in from the Top Block Container.

#main_div, #main_div1, #block1, #block2, #block3, #block4{
  border:2px solid red;
  position:absolute;
  height:80px;
}
<html>
  <head></head>
  <body>
    <div id ="main_div" style="position: relative; width:100%;"> 
      <div id="block1" style="top:2px; left:2px; width:100px;">First Block</div>
      <div id="block2" style="top:2px; left:110px;width:100px;">Second Block</div>
    </div>
    
    <div id ="main_div1" style="position: relative; width:100%;"> 
      <div id="block3" style="top:2px; left:2px; width:100px;">Third Block</div>
      <div id="block4" style="top:2px; left:110px;width:100px;">Fourth Block</div>
    </div>
    
    
  </body>
  </html>

回答1:

position="absolute" is a shorthand for absolute-position="absolute" relative-position="static". An fo:block-container with absolute-position="absolute" is taken out of the normal flow (see http://www.w3.org/TR/xsl11/#absolute-position), so the containing fo:block and fo:block-container effectively have no content, and have no height because they have no content. So your blocks overlap because they are relative to two zero-height fo:block-container that are effectively on top of each other.

If I understand your requirement correctly, you can get what you want by specifying height for the fo:block-container that contain the absolutely-positioned `fo:block container:

<fo:flow flow-name="xsl-region-body">
    <fo:block-container width="100%" color="rgb(0, 0, 0)">
        <fo:block border="thin solid silver">
            <fo:block-container border="thin solid yellow" height="4in">
                <fo:block-container width="50%" left="1in" top="1in" position="absolute" border="thin solid black"><fo:block>First Block</fo:block></fo:block-container>
                <fo:block-container width="50%" left="2in" top="3in" position="absolute" border="thin solid red"><fo:block>Second Block</fo:block></fo:block-container>
            </fo:block-container>
            <fo:block-container border="thin solid purple" height="4in">
                <fo:block-container width="50%" left="1in" top="1in" position="absolute" border="thin solid green"><fo:block>Third Block</fo:block></fo:block-container>
                <fo:block-container width="50%" left="2in" top="2in" position="absolute" border="thin solid blue"><fo:block>Fourth Block</fo:block></fo:block-container>
            </fo:block-container>
        </fo:block>
    </fo:block-container>
</fo:flow>

Tested with AH Formatter.



回答2:

This solution sets the height only on the fo:block-containers for the first and third blocks of text (which should be a reasonable constraint, as otherwise these blocks would respectively overlap the second and the fourth ones):

<fo:flow flow-name="xsl-region-body">
   <fo:block-container width="100%" color="rgb(0, 0, 0)" border="thin solid silver">
      <fo:block-container border="thin solid yellow">
         <fo:block-container width="50%" start-indent="1in" margin-top="1in" height="2in" border="thin solid black"><fo:block start-indent="0in">First Block</fo:block></fo:block-container>
         <fo:block-container width="50%" start-indent="2in" border="thin solid red"><fo:block start-indent="0in">Second Block</fo:block></fo:block-container>
      </fo:block-container>
      <fo:block-container border="thin solid purple">
         <fo:block-container width="50%" start-indent="1in" margin-top="1in" height="1in" border="thin solid green"><fo:block start-indent="0in">Third Block</fo:block></fo:block-container>
         <fo:block-container width="50%" start-indent="2in" border="thin solid blue"><fo:block start-indent="0in">Fourth Block</fo:block></fo:block-container>
      </fo:block-container>
   </fo:block-container>
</fo:flow>
  • the fo:block-containers are not given an absolute positioning
  • start-indent is used instead of left, and it must be set to 0 in the inner fo:blocks to avoid an unwanted inherited indentation
  • margin-top and height are used instead of top

The coloured borders are shamelessly copied from Tony Graham's answer: they are really helpful to see size and position of the different areas.

Tested with FOP 1.1, 2.0 and 2.1 (I'm fairly confident the other formatters would produce the same output too).